Update timothy test Makefile
[yaffs2.git] / direct / yaffsfs.c
1 /*
2  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3  *
4  * Copyright (C) 2002-2011 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"
21
22 #define YAFFSFS_MAX_SYMLINK_DEREFERENCES 5
23
24 #ifndef NULL
25 #define NULL ((void *)0)
26 #endif
27
28
29 /* YAFFSFS_RW_SIZE must be a power of 2 */
30 #define YAFFSFS_RW_SHIFT (13)
31 #define YAFFSFS_RW_SIZE  (1<<YAFFSFS_RW_SHIFT)
32
33 /* Some forward references */
34 static struct yaffs_obj *yaffsfs_FindObject(struct yaffs_obj *relativeDirectory,
35                         const YCHAR *path,
36                         int symDepth, int getEquiv,
37                         struct yaffs_obj **dirOut,
38                         int *notDir, int *loop);
39
40 static void yaffsfs_RemoveObjectCallback(struct yaffs_obj *obj);
41
42 unsigned int yaffs_wr_attempts;
43
44 /*
45  * Handle management.
46  * There are open inodes in yaffsfs_Inode.
47  * There are open file descriptors in yaffsfs_FileDes.
48  * There are open handles in yaffsfs_FileDes.
49  *
50  * Things are structured this way to be like the Linux VFS model
51  * so that interactions with the yaffs guts calls are similar.
52  * That means more common code paths and less special code.
53  * That means better testing etc.
54  *
55  * We have 3 layers because:
56  * A handle is different than an fd because you can use dup()
57  * to create a new handle that accesses the *same* fd. The two
58  * handles will use the same offset (part of the fd). We only close
59  * down the fd when there are no more handles accessing it.
60  *
61  * More than one fd can currently access one file, but each fd
62  * has its own permsiions and offset.
63  */
64
65 typedef struct {
66         int count;      /* Number of handles accessing this inode */
67         struct yaffs_obj *iObj;
68 } yaffsfs_Inode;
69
70 typedef struct{
71         u8      reading:1;
72         u8      writing:1;
73         u8      append:1;
74         u8      shareRead:1;
75         u8      shareWrite:1;
76         int     inodeId:12;     /* Index to corresponding yaffsfs_Inode */
77         int     handleCount:10; /* Number of handles for this fd */
78         loff_t  position;               /* current position in file */
79 }yaffsfs_FileDes;
80
81 typedef struct {
82         short int fdId;
83         short int useCount;
84 } yaffsfs_Handle;
85
86
87 typedef struct
88 {
89         yaffs_dirent de;                /* directory entry being used by this dsc */
90         YCHAR name[NAME_MAX+1];         /* name of directory being searched */
91         struct yaffs_obj *dirObj;           /* ptr to directory being searched */
92         struct yaffs_obj *nextReturn;       /* obj to be returned by next readddir */
93         struct list_head others;
94         int offset:20;
95         unsigned inUse:1;
96 } yaffsfs_DirectorySearchContext;
97
98
99 static yaffsfs_DirectorySearchContext yaffsfs_dsc[YAFFSFS_N_DSC];
100 static yaffsfs_Inode yaffsfs_inode[YAFFSFS_N_HANDLES];
101 static yaffsfs_FileDes yaffsfs_fd[YAFFSFS_N_HANDLES];
102 static yaffsfs_Handle yaffsfs_handle[YAFFSFS_N_HANDLES];
103
104 static int yaffsfs_handlesInitialised;
105
106
107 unsigned yaffs_set_trace(unsigned  tm)
108 {
109         yaffs_trace_mask = tm;
110         return yaffs_trace_mask;
111 }
112
113 unsigned yaffs_get_trace(void)
114 {
115         return yaffs_trace_mask;
116 }
117
118 /*
119  * yaffsfs_InitHandle
120  * Inilitalise handle management on start-up.
121  */
122
123 static void yaffsfs_InitHandles(void)
124 {
125         int i;
126         if(yaffsfs_handlesInitialised)
127                 return;
128
129         memset(yaffsfs_inode, 0, sizeof(yaffsfs_inode));
130         memset(yaffsfs_fd, 0, sizeof(yaffsfs_fd));
131         memset(yaffsfs_handle, 0, sizeof(yaffsfs_handle));
132         memset(yaffsfs_dsc, 0, sizeof(yaffsfs_dsc));
133
134         for(i = 0; i < YAFFSFS_N_HANDLES; i++)
135                 yaffsfs_fd[i].inodeId = -1;
136         for(i = 0; i < YAFFSFS_N_HANDLES; i++)
137                 yaffsfs_handle[i].fdId = -1;
138 }
139
140 static yaffsfs_Handle *yaffsfs_HandleToPointer(int h)
141 {
142         if(h >= 0 && h < YAFFSFS_N_HANDLES)
143                 return &yaffsfs_handle[h];
144         return NULL;
145 }
146
147 static yaffsfs_FileDes *yaffsfs_HandleToFileDes(int handle)
148 {
149         yaffsfs_Handle *h = yaffsfs_HandleToPointer(handle);
150
151         if(h && h->useCount > 0 && h->fdId >= 0 && h->fdId < YAFFSFS_N_HANDLES)
152                 return  &yaffsfs_fd[h->fdId];
153
154         return NULL;
155 }
156
157 static yaffsfs_Inode *yaffsfs_HandleToInode(int handle)
158 {
159         yaffsfs_FileDes *fd = yaffsfs_HandleToFileDes(handle);
160
161         if(fd && fd->handleCount > 0 &&
162                 fd->inodeId >= 0 && fd->inodeId < YAFFSFS_N_HANDLES)
163                 return  &yaffsfs_inode[fd->inodeId];
164
165         return NULL;
166 }
167
168 static struct yaffs_obj *yaffsfs_HandleToObject(int handle)
169 {
170         yaffsfs_Inode *in = yaffsfs_HandleToInode(handle);
171
172         if(in)
173                 return in->iObj;
174
175         return NULL;
176 }
177
178 /*
179  * yaffsfs_FindInodeIdForObject
180  * Find the inode entry for an object, if it exists.
181  */
182
183 static int yaffsfs_FindInodeIdForObject(struct yaffs_obj *obj)
184 {
185         int i;
186         int ret = -1;
187
188         if(obj)
189                 obj = yaffs_get_equivalent_obj(obj);
190
191         /* Look for it in open inode table*/
192         for(i = 0; i < YAFFSFS_N_HANDLES && ret < 0; i++){
193                 if(yaffsfs_inode[i].iObj == obj)
194                         ret = i;
195         }
196         return ret;
197 }
198
199 /*
200  * yaffsfs_GetInodeIdForObject
201  * Grab an inode entry when opening a new inode.
202  */
203 static int yaffsfs_GetInodeIdForObject(struct yaffs_obj *obj)
204 {
205         int i;
206         int ret;
207         yaffsfs_Inode *in = NULL;
208
209         if(obj)
210                 obj = yaffs_get_equivalent_obj(obj);
211
212         ret = yaffsfs_FindInodeIdForObject(obj);
213
214         for(i = 0; i < YAFFSFS_N_HANDLES && ret < 0; i++){
215                 if(!yaffsfs_inode[i].iObj)
216                         ret = i;
217         }
218
219         if(ret>=0){
220                 in = &yaffsfs_inode[ret];
221                 if(!in->iObj)
222                         in->count = 0;
223                 in->iObj = obj;
224                 in->count++;
225         }
226
227
228         return ret;
229 }
230
231
232 static int yaffsfs_CountHandles(struct yaffs_obj *obj)
233 {
234         int i = yaffsfs_FindInodeIdForObject(obj);
235
236         if(i >= 0)
237                 return yaffsfs_inode[i].count;
238         else
239                 return 0;
240 }
241
242 static void yaffsfs_ReleaseInode(yaffsfs_Inode *in)
243 {
244         struct yaffs_obj *obj;
245
246         obj = in->iObj;
247
248         if(obj->unlinked)
249                 yaffs_del_obj(obj);
250
251         obj->my_inode = NULL;
252         in->iObj = NULL;
253
254 }
255
256 static void yaffsfs_PutInode(int inodeId)
257 {
258         if(inodeId >= 0 && inodeId < YAFFSFS_N_HANDLES){
259                 yaffsfs_Inode *in = & yaffsfs_inode[inodeId];
260                 in->count--;
261                 if(in->count <= 0){
262                         yaffsfs_ReleaseInode(in);
263                         in->count = 0;
264                 }
265         }
266 }
267
268
269
270 static int yaffsfs_NewHandle(yaffsfs_Handle **hptr)
271 {
272         int i;
273         yaffsfs_Handle *h;
274
275         for(i = 0; i < YAFFSFS_N_HANDLES; i++){
276                 h = &yaffsfs_handle[i];
277                 if(h->useCount < 1){
278                         memset(h,0,sizeof(yaffsfs_Handle));
279                         h->fdId=-1;
280                         h->useCount=1;
281                         if(hptr)
282                                 *hptr = h;
283                         return i;
284                 }
285         }
286         return -1;
287 }
288
289 static int yaffsfs_NewHandleAndFileDes(void)
290 {
291         int i;
292         yaffsfs_FileDes *fd;
293         yaffsfs_Handle  *h = NULL;
294         int handle = yaffsfs_NewHandle(&h);
295
296         if(handle < 0)
297                 return -1;
298
299         for(i = 0; i < YAFFSFS_N_HANDLES; i++){
300                 fd = &yaffsfs_fd[i];
301                 if(fd->handleCount < 1){
302                         memset(fd,0,sizeof(yaffsfs_FileDes));
303                         fd->inodeId=-1;
304                         fd->handleCount=1;
305                         h->fdId = i;
306                         return handle;
307                 }
308         }
309
310         /* Dump the handle because we could not get a fd */
311         h->useCount = 0;
312         return -1;
313 }
314
315 /*
316  * yaffs_get_handle
317  * Increase use of handle when reading/writing a file
318  * Also gets the file descriptor.
319  */
320
321 static int yaffsfs_GetHandle(int handle)
322 {
323         yaffsfs_Handle *h = yaffsfs_HandleToPointer(handle);
324
325         if(h && h->useCount > 0){
326                 h->useCount++;
327                 return 0;
328         }
329         return -1;
330 }
331
332 /*
333  * yaffs_put_handle
334  * Let go of a handle when closing a file or aborting an open or
335  * ending a read or write.
336  */
337
338 static int yaffsfs_PutFileDes(int fdId)
339 {
340         yaffsfs_FileDes *fd;
341
342         if(fdId >= 0 && fdId < YAFFSFS_N_HANDLES){
343                 fd = &yaffsfs_fd[fdId];
344                 fd->handleCount--;
345                 if(fd->handleCount < 1){
346                         if(fd->inodeId >= 0){
347                                 yaffsfs_PutInode(fd->inodeId);
348                                 fd->inodeId = -1;
349                         }
350                 }
351         }
352         return 0;
353 }
354 static int yaffsfs_PutHandle(int handle)
355 {
356         yaffsfs_Handle *h = yaffsfs_HandleToPointer(handle);
357
358         if(h && h->useCount > 0){
359                 h->useCount--;
360                 if(h->useCount < 1){
361                         yaffsfs_PutFileDes(h->fdId);
362                         h->fdId = -1;
363                 }
364         }
365
366         return 0;
367 }
368
369 static void yaffsfs_BreakDeviceHandles(struct yaffs_dev *dev)
370 {
371         yaffsfs_FileDes *fd;
372         yaffsfs_Handle *h;
373         struct yaffs_obj *obj;
374         int i;
375         for(i = 0; i < YAFFSFS_N_HANDLES; i++){
376                 h = yaffsfs_HandleToPointer(i);
377                 fd = yaffsfs_HandleToFileDes(i);
378                 obj = yaffsfs_HandleToObject(i);
379                 if(h && h->useCount > 0){
380                         h->useCount = 0;
381                         h->fdId = 0;
382                 }
383                 if(fd && fd->handleCount>0 && obj && obj->my_dev == dev){
384
385                         fd->handleCount = 0;
386                         yaffsfs_PutInode(fd->inodeId);
387                         fd->inodeId = -1;
388                 }
389         }
390 }
391
392
393
394
395 /*
396  *  Stuff to handle names.
397  */
398 #ifdef CONFIG_YAFFS_CASE_INSENSITIVE
399
400 static int yaffs_toupper(YCHAR a)
401 {
402         if(a >= 'a' && a <= 'z')
403                 return (a - 'a') + 'A';
404         else
405                 return a;
406 }
407
408 int yaffsfs_Match(YCHAR a, YCHAR b)
409 {
410         return (yaffs_toupper(a) == yaffs_toupper(b));
411 }
412 #else
413 int yaffsfs_Match(YCHAR a, YCHAR b)
414 {
415         /* case sensitive */
416         return (a == b);
417 }
418 #endif
419
420 int yaffsfs_IsPathDivider(YCHAR ch)
421 {
422         const YCHAR *str = YAFFS_PATH_DIVIDERS;
423
424         while(*str){
425                 if(*str == ch)
426                         return 1;
427                 str++;
428         }
429
430         return 0;
431 }
432
433 int yaffsfs_CheckNameLength(const char *name)
434 {
435         int retVal = 0;
436
437         int nameLength = yaffs_strnlen(name,YAFFS_MAX_NAME_LENGTH+1);
438
439         if(nameLength == 0){
440                 yaffsfs_SetError(-ENOENT);
441                 retVal = -1;
442         } else if (nameLength > YAFFS_MAX_NAME_LENGTH){
443                 yaffsfs_SetError(-ENAMETOOLONG);
444                 retVal = -1;
445         }
446
447         return retVal;
448 }
449
450
451 static int yaffsfs_alt_dir_path(const YCHAR *path, YCHAR **ret_path)
452 {
453         YCHAR *alt_path = NULL;
454         int path_length;
455         int i;
456
457         /*
458          * We don't have a definition for max path length.
459          * We will use 3 * max name length instead.
460          */
461         *ret_path = NULL;
462         path_length = yaffs_strnlen(path,(YAFFS_MAX_NAME_LENGTH+1)*3 +1);
463
464         /* If the last character is a path divider, then we need to
465          * trim it back so that the name look-up works properly.
466          * eg. /foo/new_dir/ -> /foo/newdir
467          * Curveball: Need to handle multiple path dividers:
468          * eg. /foof/sdfse///// -> /foo/sdfse
469          */
470         if(path_length > 0 &&
471                 yaffsfs_IsPathDivider(path[path_length-1])){
472                 alt_path = kmalloc(path_length + 1, 0);
473                 if(!alt_path)
474                         return -1;
475                 yaffs_strcpy(alt_path, path);
476                 for(i = path_length-1;
477                         i >= 0 && yaffsfs_IsPathDivider(alt_path[i]);
478                         i--)
479                         alt_path[i] = (YCHAR) 0;
480         }
481         *ret_path = alt_path;
482         return 0;
483 }
484
485
486 LIST_HEAD(yaffsfs_deviceList);
487
488 /*
489  * yaffsfs_FindDevice
490  * yaffsfs_FindRoot
491  * Scan the configuration list to find the device
492  * Curveballs: Should match paths that end in '/' too
493  * Curveball2 Might have "/x/ and "/x/y". Need to return the longest match
494  */
495 static struct yaffs_dev *yaffsfs_FindDevice(const YCHAR *path, YCHAR **restOfPath)
496 {
497         struct list_head *cfg;
498         const YCHAR *leftOver;
499         const YCHAR *p;
500         struct yaffs_dev *retval = NULL;
501         struct yaffs_dev *dev = NULL;
502         int thisMatchLength;
503         int longestMatch = -1;
504         int matching;
505
506         /*
507          * Check all configs, choose the one that:
508          * 1) Actually matches a prefix (ie /a amd /abc will not match
509          * 2) Matches the longest.
510          */
511         list_for_each(cfg, &yaffsfs_deviceList){
512                 dev = list_entry(cfg, struct yaffs_dev, dev_list);
513                 leftOver = path;
514                 p = dev->param.name;
515                 thisMatchLength = 0;
516                 matching = 1;
517
518
519                 while(matching && *p && *leftOver){
520                         /* Skip over any /s */
521                         while(yaffsfs_IsPathDivider(*p))
522                               p++;
523
524                         /* Skip over any /s */
525                         while(yaffsfs_IsPathDivider(*leftOver))
526                               leftOver++;
527
528                         /* Now match the text part */
529                         while(matching &&
530                               *p && !yaffsfs_IsPathDivider(*p) &&
531                               *leftOver && !yaffsfs_IsPathDivider(*leftOver)){
532                                 if(yaffsfs_Match(*p,*leftOver)){
533                                         p++;
534                                         leftOver++;
535                                         thisMatchLength++;
536                                 } else {
537                                         matching = 0;
538                                 }
539                         }
540                 }
541
542                 /* Skip over any /s in leftOver */
543                 while(yaffsfs_IsPathDivider(*leftOver))
544                       leftOver++;
545
546                 // Skip over any /s in p
547                 while(yaffsfs_IsPathDivider(*p))
548                       p++;
549
550                 // p should now be at the end of the string (ie. fully matched)
551                 if(*p)
552                         matching = 0;
553
554                 if( matching && (thisMatchLength > longestMatch))
555                 {
556                         // Matched prefix
557                         *restOfPath = (YCHAR *)leftOver;
558                         retval = dev;
559                         longestMatch = thisMatchLength;
560                 }
561
562         }
563         return retval;
564 }
565
566 static int yaffsfs_CheckPath(const YCHAR *path)
567 {
568         int n=0;
569         int divs=0;
570         while(*path && n < YAFFS_MAX_NAME_LENGTH && divs < 100){
571                 if(yaffsfs_IsPathDivider(*path)){
572                         n=0;
573                         divs++;
574                 } else
575                         n++;
576                 path++;
577         }
578
579         return (*path) ? -1 : 0;
580 }
581
582 /* FindMountPoint only returns a dev entry if the path is a mount point */
583 static struct yaffs_dev *yaffsfs_FindMountPoint(const YCHAR *path)
584 {
585         struct yaffs_dev *dev;
586         YCHAR *restOfPath=NULL;
587         dev = yaffsfs_FindDevice(path,&restOfPath);
588         if(dev && restOfPath && *restOfPath)
589                 dev = NULL;
590         return dev;
591 }
592
593 static struct yaffs_obj *yaffsfs_FindRoot(const YCHAR *path, YCHAR **restOfPath)
594 {
595
596         struct yaffs_dev *dev;
597
598         dev= yaffsfs_FindDevice(path,restOfPath);
599         if(dev && dev->is_mounted){
600                 return dev->root_dir;
601         }
602         return NULL;
603 }
604
605 static struct yaffs_obj *yaffsfs_FollowLink(struct yaffs_obj *obj,
606                                         int symDepth, int *loop)
607 {
608
609         if(obj)
610                 obj = yaffs_get_equivalent_obj(obj);
611
612         while(obj && obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK){
613                 YCHAR *alias = obj->variant.symlink_variant.alias;
614
615                 if(yaffsfs_IsPathDivider(*alias))
616                         /* Starts with a /, need to scan from root up */
617                         obj = yaffsfs_FindObject(NULL,alias,symDepth++,
618                                                 1,NULL,NULL,loop);
619                 else
620                         /* Relative to here, so use the parent of the symlink as a start */
621                         obj = yaffsfs_FindObject(obj->parent,alias,symDepth++,
622                                                 1,NULL,NULL,loop);
623         }
624         return obj;
625 }
626
627
628 /*
629  * yaffsfs_FindDirectory
630  * Parse a path to determine the directory and the name within the directory.
631  *
632  * eg. "/data/xx/ff" --> puts name="ff" and returns the directory "/data/xx"
633  */
634 static struct yaffs_obj *yaffsfs_DoFindDirectory(struct yaffs_obj *startDir,
635                                 const YCHAR *path, YCHAR **name, int symDepth,
636                                 int *notDir,int *loop)
637 {
638         struct yaffs_obj *dir;
639         YCHAR *restOfPath;
640         YCHAR str[YAFFS_MAX_NAME_LENGTH+1];
641         int i;
642
643         if(symDepth > YAFFSFS_MAX_SYMLINK_DEREFERENCES){
644                 if(loop)
645                         *loop = 1;
646                 return NULL;
647         }
648
649         if(startDir){
650                 dir = startDir;
651                 restOfPath = (YCHAR *)path;
652         }
653         else
654                 dir = yaffsfs_FindRoot(path,&restOfPath);
655
656
657         while(dir){
658                 /*
659                  * parse off /.
660                  * curve ball: also throw away surplus '/'
661                  * eg. "/ram/x////ff" gets treated the same as "/ram/x/ff"
662                  */
663                 while(yaffsfs_IsPathDivider(*restOfPath))
664                         restOfPath++; /* get rid of '/' */
665
666                 *name = restOfPath;
667                 i = 0;
668
669                 while(*restOfPath && !yaffsfs_IsPathDivider(*restOfPath)){
670                         if (i < YAFFS_MAX_NAME_LENGTH){
671                                 str[i] = *restOfPath;
672                                 str[i+1] = '\0';
673                                 i++;
674                         }
675                         restOfPath++;
676                 }
677
678                 if(!*restOfPath)
679                         /* got to the end of the string */
680                         return dir;
681                 else{
682                         if(yaffs_strcmp(str,_Y(".")) == 0){
683                                 /* Do nothing */
684                         } else if(yaffs_strcmp(str,_Y("..")) == 0) {
685                                 dir = dir->parent;
686                         } else{
687                                 dir = yaffs_find_by_name(dir,str);
688
689                                 dir = yaffsfs_FollowLink(dir,symDepth,loop);
690
691                                 if(dir && dir->variant_type !=
692                                         YAFFS_OBJECT_TYPE_DIRECTORY){
693                                         if(notDir)
694                                                 *notDir = 1;
695                                         dir = NULL;
696                                 }
697
698                         }
699                 }
700         }
701         /* directory did not exist. */
702         return NULL;
703 }
704
705 static struct yaffs_obj *yaffsfs_FindDirectory(struct yaffs_obj *relDir,
706                                         const YCHAR *path,
707                                         YCHAR **name,
708                                         int symDepth,
709                                         int *notDir,
710                                         int *loop)
711 {
712         return yaffsfs_DoFindDirectory(relDir,path,name,symDepth,notDir,loop);
713 }
714
715 /*
716  * yaffsfs_FindObject turns a path for an existing object into the object
717  */
718 static struct yaffs_obj *yaffsfs_FindObject(struct yaffs_obj *relDir,
719                         const YCHAR *path,int symDepth, int getEquiv,
720                         struct yaffs_obj **dirOut, int *notDir,int *loop)
721 {
722         struct yaffs_obj *dir;
723         struct yaffs_obj *obj;
724         YCHAR *name;
725
726         dir = yaffsfs_FindDirectory(relDir,path,&name,symDepth,notDir,loop);
727
728         if(dirOut)
729                 *dirOut =  dir;
730
731         if(dir && *name)
732                 obj = yaffs_find_by_name(dir,name);
733         else
734                 obj = dir;
735
736         if(getEquiv)
737                 obj = yaffs_get_equivalent_obj(obj);
738
739         return obj;
740 }
741
742
743 /*************************************************************************
744  *      Start of yaffsfs visible functions.
745  *************************************************************************/
746
747 int yaffs_dup(int handle)
748 {
749         int newHandleNumber = -1;
750         yaffsfs_FileDes *existingFD = NULL;
751         yaffsfs_Handle *existingHandle = NULL;
752         yaffsfs_Handle *newHandle = NULL;
753
754         yaffsfs_Lock();
755         existingHandle = yaffsfs_HandleToPointer(handle);
756         existingFD = yaffsfs_HandleToFileDes(handle);
757         if(existingFD)
758                 newHandleNumber = yaffsfs_NewHandle(&newHandle);
759         if(newHandle){
760                 newHandle->fdId = existingHandle->fdId;
761                 existingFD->handleCount++;
762         }
763
764         yaffsfs_Unlock();
765
766         if(!existingFD)
767                 yaffsfs_SetError(-EBADF);
768         else if (!newHandle)
769                 yaffsfs_SetError(-ENOMEM);
770
771         return newHandleNumber;
772
773 }
774
775 static int yaffsfs_TooManyObjects(struct yaffs_dev *dev)
776 {
777         int current_objects = dev->n_obj - dev->n_deleted_files;
778
779         if(dev->param.max_objects && current_objects > dev->param.max_objects)
780                 return 1;
781         else
782                 return 0;
783 }
784
785 int yaffs_open_sharing(const YCHAR *path, int oflag, int mode, int sharing)
786 {
787         struct yaffs_obj *obj = NULL;
788         struct yaffs_obj *dir = NULL;
789         YCHAR *name;
790         int handle = -1;
791         yaffsfs_FileDes *fd = NULL;
792         int openDenied = 0;
793         int symDepth = 0;
794         int errorReported = 0;
795         int rwflags = oflag & ( O_RDWR | O_RDONLY | O_WRONLY);
796         u8 shareRead = (sharing & YAFFS_SHARE_READ) ?  1 : 0;
797         u8 shareWrite = (sharing & YAFFS_SHARE_WRITE) ? 1 : 0;
798         u8 sharedReadAllowed;
799         u8 sharedWriteAllowed;
800         u8 alreadyReading;
801         u8 alreadyWriting;
802         u8 readRequested;
803         u8 writeRequested;
804         int notDir = 0;
805         int loop = 0;
806
807         if(!path) {
808                 yaffsfs_SetError(-EFAULT);
809                 return -1;
810         }
811
812         if(yaffsfs_CheckPath(path) < 0){
813                 yaffsfs_SetError(-ENAMETOOLONG);
814                 return -1;
815         }
816
817         /* O_EXCL only has meaning if O_CREAT is specified */
818         if(!(oflag & O_CREAT))
819                 oflag &= ~(O_EXCL);
820
821         /* O_TRUNC has no meaning if (O_CREAT | O_EXCL) is specified */
822         if( (oflag & O_CREAT) & (oflag & O_EXCL))
823                 oflag &= ~(O_TRUNC);
824
825         /* Todo: Are there any more flag combos to sanitise ? */
826
827         /* Figure out if reading or writing is requested */
828
829         readRequested = (rwflags == O_RDWR || rwflags == O_RDONLY) ? 1 : 0;
830         writeRequested = (rwflags == O_RDWR || rwflags == O_WRONLY) ? 1 : 0;
831
832         yaffsfs_Lock();
833
834         handle = yaffsfs_NewHandleAndFileDes();
835
836         if(handle < 0){
837                 yaffsfs_SetError(-ENFILE);
838                 errorReported = 1;
839         } else {
840
841                 fd = yaffsfs_HandleToFileDes(handle);
842
843                 /* try to find the exisiting object */
844                 obj = yaffsfs_FindObject(NULL,path,0,1,NULL,NULL,NULL);
845
846                 obj = yaffsfs_FollowLink(obj,symDepth++,&loop);
847
848                 if(obj &&
849                         obj->variant_type != YAFFS_OBJECT_TYPE_FILE &&
850                         obj->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
851                         obj = NULL;
852
853
854                 if(obj){
855
856                         /* The file already exists or it might be a directory */
857
858                         /* If it is a directory then we can't open it as a file */
859                         if(obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY){
860                                 openDenied = 1;
861                                 yaffsfs_SetError(-EISDIR);
862                                 errorReported = 1;
863                         }
864
865                         /* Open should fail if O_CREAT and O_EXCL are specified since
866                          * the file exists
867                          */
868                         if(!errorReported && (oflag & O_EXCL) && (oflag & O_CREAT)){
869                                 openDenied = 1;
870                                 yaffsfs_SetError(-EEXIST);
871                                 errorReported = 1;
872                         }
873
874                         /* Check file permissions */
875                         if( readRequested && !(obj->yst_mode & S_IREAD))
876                                 openDenied = 1;
877
878                         if( writeRequested && !(obj->yst_mode & S_IWRITE))
879                                 openDenied = 1;
880
881                         if( !errorReported && writeRequested &&
882                                 obj->my_dev->read_only){
883                                 openDenied = 1;
884                                 yaffsfs_SetError(-EROFS);
885                                 errorReported = 1;
886                         }
887
888                         if(openDenied && !errorReported ) {
889                                 /* Error if the file exists but permissions are refused. */
890                                 yaffsfs_SetError(-EACCES);
891                                 errorReported = 1;
892                         }
893
894                         /* Check sharing of an existing object. */
895                         if(!openDenied){
896                                 yaffsfs_FileDes *fdx;
897                                 int i;
898
899                                 sharedReadAllowed = 1;
900                                 sharedWriteAllowed = 1;
901                                 alreadyReading = 0;
902                                 alreadyWriting = 0;
903                                 for( i = 0; i < YAFFSFS_N_HANDLES; i++){
904                                         fdx = &yaffsfs_fd[i];
905                                         if(fdx->handleCount > 0 &&
906                                                 fdx->inodeId >= 0 &&
907                                                 yaffsfs_inode[fdx->inodeId].iObj == obj){
908                                                 if(!fdx->shareRead)
909                                                         sharedReadAllowed = 0;
910                                                 if(!fdx->shareWrite)
911                                                         sharedWriteAllowed = 0;
912                                                 if(fdx->reading)
913                                                         alreadyReading = 1;
914                                                 if(fdx->writing)
915                                                         alreadyWriting = 1;
916                                         }
917                                 }
918
919
920
921                                 if((!sharedReadAllowed && readRequested)||
922                                         (!shareRead  && alreadyReading) ||
923                                         (!sharedWriteAllowed && writeRequested) ||
924                                         (!shareWrite && alreadyWriting)){
925                                         openDenied = 1;
926                                         yaffsfs_SetError(-EBUSY);
927                                         errorReported=1;
928                                 }
929                         }
930
931                 }
932
933                 /* If we could not open an existing object, then let's see if
934                  * the directory exists. If not, error.
935                  */
936                 if(!obj && !errorReported){
937                         dir = yaffsfs_FindDirectory(NULL,path,&name,0,&notDir,&loop);
938                         if(!dir && notDir){
939                                 yaffsfs_SetError(-ENOTDIR);
940                                 errorReported = 1;
941                         } else if(loop){
942                                 yaffsfs_SetError(-ELOOP);
943                                 errorReported = 1;
944                         } else  if(!dir){
945                                 yaffsfs_SetError(-ENOENT);
946                                 errorReported = 1;
947                         }
948                 }
949
950                 if(!obj && dir && !errorReported && (oflag & O_CREAT)) {
951                         /* Let's see if we can create this file if it does not exist. */
952                         if(dir->my_dev->read_only){
953                                 yaffsfs_SetError(-EROFS);
954                                 errorReported = 1;
955                         } else if(yaffsfs_TooManyObjects(dir->my_dev)) {
956                                 yaffsfs_SetError(-ENFILE);
957                                 errorReported = 1;
958                         } else
959                                 obj = yaffs_create_file(dir,name,mode,0,0);
960
961                         if(!obj && !errorReported){
962                                 yaffsfs_SetError(-ENOSPC);
963                                 errorReported = 1;
964                         }
965                 }
966
967                 if(!obj && dir && !errorReported && !(oflag & O_CREAT)) {
968                         /* Error if the file does not exist and CREAT is not set. */
969                         yaffsfs_SetError(-ENOENT);
970                         errorReported = 1;
971                 }
972
973                 if(obj && !openDenied) {
974                         int inodeId = yaffsfs_GetInodeIdForObject(obj);
975
976                         if(inodeId<0) {
977                                 /*
978                                  * Todo: Fix any problem if inodes run out, though that
979                                  * can't happen if the number of inode items >= number of handles.
980                                  */
981                         }
982
983                         fd->inodeId = inodeId;
984                         fd->reading = readRequested;
985                         fd->writing = writeRequested;
986                         fd->append =  (oflag & O_APPEND) ? 1 : 0;
987                         fd->position = 0;
988                         fd->shareRead = shareRead;
989                         fd->shareWrite = shareWrite;
990
991                         /* Hook inode to object */
992                         obj->my_inode = (void*) &yaffsfs_inode[inodeId];
993
994                         if((oflag & O_TRUNC) && fd->writing)
995                                 yaffs_resize_file(obj,0);
996                 } else {
997                         yaffsfs_PutHandle(handle);
998                         if(!errorReported)
999                                 yaffsfs_SetError(0); /* Problem */
1000                         handle = -1;
1001                 }
1002         }
1003
1004         yaffsfs_Unlock();
1005
1006         return handle;
1007 }
1008
1009 int yaffs_open(const YCHAR *path, int oflag, int mode)
1010 {
1011         return yaffs_open_sharing(path, oflag, mode,
1012                         YAFFS_SHARE_READ | YAFFS_SHARE_WRITE);
1013 }
1014
1015 int yaffs_Dofsync(int handle,int datasync)
1016 {
1017         int retVal = -1;
1018         struct yaffs_obj *obj;
1019
1020         yaffsfs_Lock();
1021
1022         obj = yaffsfs_HandleToObject(handle);
1023
1024         if(!obj)
1025                 yaffsfs_SetError(-EBADF);
1026         else if(obj->my_dev->read_only)
1027                 yaffsfs_SetError(-EROFS);
1028         else {
1029                 yaffs_flush_file(obj,1,datasync);
1030                 retVal = 0;
1031         }
1032
1033         yaffsfs_Unlock();
1034
1035         return retVal;
1036 }
1037
1038 int yaffs_fsync(int handle)
1039 {
1040         return yaffs_Dofsync(handle,0);
1041 }
1042
1043 int yaffs_flush(int handle)
1044 {
1045         return yaffs_fsync(handle);
1046 }
1047
1048 int yaffs_fdatasync(int handle)
1049 {
1050         return yaffs_Dofsync(handle,1);
1051 }
1052
1053 int yaffs_close(int handle)
1054 {
1055         yaffsfs_Handle *h = NULL;
1056         struct yaffs_obj *obj = NULL;
1057         int retVal = -1;
1058
1059         yaffsfs_Lock();
1060
1061         h = yaffsfs_HandleToPointer(handle);
1062         obj = yaffsfs_HandleToObject(handle);
1063
1064         if(!h  || !obj)
1065                 yaffsfs_SetError(-EBADF);
1066         else {
1067                 /* clean up */
1068                 yaffs_flush_file(obj,1,0);
1069                 yaffsfs_PutHandle(handle);
1070                 retVal = 0;
1071         }
1072
1073         yaffsfs_Unlock();
1074
1075         return retVal;
1076 }
1077
1078
1079
1080 int yaffsfs_do_read(int handle, void *vbuf, unsigned int nbyte, int isPread, loff_t offset)
1081 {
1082         yaffsfs_FileDes *fd = NULL;
1083         struct yaffs_obj *obj = NULL;
1084         loff_t pos = 0;
1085         loff_t startPos = 0;
1086         loff_t endPos = 0;
1087         int nRead = 0;
1088         int nToRead = 0;
1089         int totalRead = 0;
1090         loff_t maxRead;
1091         u8 *buf = (u8 *)vbuf;
1092
1093         if(!vbuf){
1094                 yaffsfs_SetError(-EFAULT);
1095                 return -1;
1096         }
1097
1098         yaffsfs_Lock();
1099         fd = yaffsfs_HandleToFileDes(handle);
1100         obj = yaffsfs_HandleToObject(handle);
1101
1102         if(!fd || !obj){
1103                 /* bad handle */
1104                 yaffsfs_SetError(-EBADF);
1105                 totalRead = -1;
1106         } else if(!fd->reading){
1107                 /* Not a reading handle */
1108                 yaffsfs_SetError(-EINVAL);
1109                 totalRead = -1;
1110         } else if(nbyte > YAFFS_MAX_FILE_SIZE){
1111                 yaffsfs_SetError(-EINVAL);
1112                 totalRead = -1;
1113         } else {
1114                 if(isPread)
1115                         startPos = offset;
1116                 else
1117                         startPos = fd->position;
1118
1119                 pos = startPos;
1120
1121                 if(yaffs_get_obj_length(obj) > pos)
1122                         maxRead = yaffs_get_obj_length(obj) - pos;
1123                 else
1124                         maxRead = 0;
1125
1126                 if(nbyte > maxRead)
1127                         nbyte = maxRead;
1128
1129
1130                 yaffsfs_GetHandle(handle);
1131
1132                 endPos = pos + nbyte;
1133
1134                 if(pos < 0 || pos > YAFFS_MAX_FILE_SIZE ||
1135                         nbyte > YAFFS_MAX_FILE_SIZE ||
1136                         endPos < 0 || endPos > YAFFS_MAX_FILE_SIZE){
1137                         totalRead = -1;
1138                         nbyte = 0;
1139                 }
1140
1141                 while(nbyte > 0) {
1142                         nToRead = YAFFSFS_RW_SIZE - (pos & (YAFFSFS_RW_SIZE -1));
1143                         if(nToRead > nbyte)
1144                                 nToRead = nbyte;
1145
1146                         /* Tricky bit...
1147                          * Need to reverify object in case the device was
1148                          * unmounted in another thread.
1149                          */
1150                         obj = yaffsfs_HandleToObject(handle);
1151                         if(!obj)
1152                                 nRead = 0;
1153                         else
1154                                 nRead = yaffs_file_rd(obj,buf,pos,nToRead);
1155
1156                         if(nRead > 0){
1157                                 totalRead += nRead;
1158                                 pos += nRead;
1159                                 buf += nRead;
1160                         }
1161
1162                         if(nRead == nToRead)
1163                                 nbyte-=nRead;
1164                         else
1165                                 nbyte = 0; /* no more to read */
1166
1167
1168                         if(nbyte > 0){
1169                                 yaffsfs_Unlock();
1170                                 yaffsfs_Lock();
1171                         }
1172
1173                 }
1174
1175                 yaffsfs_PutHandle(handle);
1176
1177                 if(!isPread) {
1178                         if(totalRead >= 0)
1179                                 fd->position = startPos + totalRead;
1180                         else
1181                                 yaffsfs_SetError(-EINVAL);
1182                 }
1183
1184         }
1185
1186         yaffsfs_Unlock();
1187
1188         return (totalRead >= 0) ? totalRead : -1;
1189
1190 }
1191
1192 int yaffs_read(int handle, void *buf, unsigned int nbyte)
1193 {
1194         return yaffsfs_do_read(handle, buf, nbyte, 0, 0);
1195 }
1196
1197 int yaffs_pread(int handle, void *buf, unsigned int nbyte, loff_t offset)
1198 {
1199         return yaffsfs_do_read(handle, buf, nbyte, 1, offset);
1200 }
1201
1202 int yaffsfs_do_write(int handle, const void *vbuf, unsigned int nbyte, int isPwrite, loff_t offset)
1203 {
1204         yaffsfs_FileDes *fd = NULL;
1205         struct yaffs_obj *obj = NULL;
1206         loff_t pos = 0;
1207         loff_t startPos = 0;
1208         loff_t endPos;
1209         int nWritten = 0;
1210         int totalWritten = 0;
1211         int write_trhrough = 0;
1212         int nToWrite = 0;
1213         const u8 *buf = (const u8 *)vbuf;
1214
1215         if(!vbuf){
1216                 yaffsfs_SetError(-EFAULT);
1217                 return -1;
1218         }
1219
1220         yaffsfs_Lock();
1221         fd = yaffsfs_HandleToFileDes(handle);
1222         obj = yaffsfs_HandleToObject(handle);
1223
1224         if(!fd || !obj){
1225                 /* bad handle */
1226                 yaffsfs_SetError(-EBADF);
1227                 totalWritten = -1;
1228         } else if(!fd->writing){
1229                 yaffsfs_SetError(-EINVAL);
1230                 totalWritten=-1;
1231         } else if(obj->my_dev->read_only){
1232                 yaffsfs_SetError(-EROFS);
1233                 totalWritten=-1;
1234         } else {
1235                 if(fd->append)
1236                         startPos = yaffs_get_obj_length(obj);
1237                 else if(isPwrite)
1238                         startPos = offset;
1239                 else
1240                         startPos = fd->position;
1241
1242                 yaffsfs_GetHandle(handle);
1243                 pos = startPos;
1244                 endPos = pos + nbyte;
1245
1246                 if(pos < 0 || pos > YAFFS_MAX_FILE_SIZE ||
1247                         nbyte > YAFFS_MAX_FILE_SIZE ||
1248                         endPos < 0 || endPos > YAFFS_MAX_FILE_SIZE){
1249                         totalWritten = -1;
1250                         nbyte = 0;
1251                 }
1252
1253                 while(nbyte > 0) {
1254
1255                         nToWrite = YAFFSFS_RW_SIZE - (pos & (YAFFSFS_RW_SIZE -1));
1256                         if(nToWrite > nbyte)
1257                                 nToWrite = nbyte;
1258
1259                         /* Tricky bit...
1260                          * Need to reverify object in case the device was
1261                          * remounted or unmounted in another thread.
1262                          */
1263                         obj = yaffsfs_HandleToObject(handle);
1264                         if(!obj || obj->my_dev->read_only)
1265                                 nWritten = 0;
1266                         else
1267                                 nWritten = yaffs_wr_file(obj,buf,pos,nToWrite,
1268                                                         write_trhrough);
1269                         if(nWritten > 0){
1270                                 totalWritten += nWritten;
1271                                 pos += nWritten;
1272                                 buf += nWritten;
1273                         }
1274
1275                         if(nWritten == nToWrite)
1276                                 nbyte -= nToWrite;
1277                         else
1278                                 nbyte = 0;
1279
1280                         if(nWritten < 1 && totalWritten < 1){
1281                                 yaffsfs_SetError(-ENOSPC);
1282                                 totalWritten = -1;
1283                         }
1284
1285                         if(nbyte > 0){
1286                                 yaffsfs_Unlock();
1287                                 yaffsfs_Lock();
1288                         }
1289                 }
1290
1291                 yaffsfs_PutHandle(handle);
1292
1293                 if(!isPwrite){
1294                         if(totalWritten > 0)
1295                                 fd->position = startPos + totalWritten;
1296                         else
1297                                 yaffsfs_SetError(-EINVAL);
1298                 }
1299         }
1300
1301         yaffsfs_Unlock();
1302
1303         return (totalWritten >= 0) ? totalWritten : -1;
1304 }
1305
1306 int yaffs_write(int fd, const void *buf, unsigned int nbyte)
1307 {
1308         return yaffsfs_do_write(fd, buf, nbyte, 0, 0);
1309 }
1310
1311 int yaffs_pwrite(int fd, const void *buf, unsigned int nbyte, loff_t offset)
1312 {
1313         return yaffsfs_do_write(fd, buf, nbyte, 1, offset);
1314 }
1315
1316
1317 int yaffs_truncate(const YCHAR *path,loff_t new_size)
1318 {
1319         struct yaffs_obj *obj = NULL;
1320         struct yaffs_obj *dir = NULL;
1321         int result = YAFFS_FAIL;
1322         int notDir = 0;
1323         int loop = 0;
1324
1325         if(!path){
1326                 yaffsfs_SetError(-EFAULT);
1327                 return -1;
1328         }
1329
1330         if(yaffsfs_CheckPath(path) < 0){
1331                 yaffsfs_SetError(-ENAMETOOLONG);
1332                 return -1;
1333         }
1334
1335         yaffsfs_Lock();
1336
1337         obj = yaffsfs_FindObject(NULL,path,0,1,&dir,&notDir,&loop);
1338         obj = yaffsfs_FollowLink(obj,0,&loop);
1339
1340         if(!dir && notDir)
1341                 yaffsfs_SetError(-ENOTDIR);
1342         else if(loop)
1343                 yaffsfs_SetError(-ELOOP);
1344         else if(!dir || !obj)
1345                 yaffsfs_SetError(-ENOENT);
1346         else if(obj->my_dev->read_only)
1347                 yaffsfs_SetError(-EROFS);
1348         else if(obj->variant_type != YAFFS_OBJECT_TYPE_FILE)
1349                 yaffsfs_SetError(-EISDIR);
1350         else if(obj->my_dev->read_only)
1351                 yaffsfs_SetError(-EROFS);
1352         else if(new_size < 0 || new_size > YAFFS_MAX_FILE_SIZE)
1353                 yaffsfs_SetError(-EINVAL);
1354         else
1355                 result = yaffs_resize_file(obj, new_size);
1356
1357         yaffsfs_Unlock();
1358
1359         return (result) ? 0 : -1;
1360 }
1361
1362 int yaffs_ftruncate(int handle, loff_t new_size)
1363 {
1364         yaffsfs_FileDes *fd = NULL;
1365         struct yaffs_obj *obj = NULL;
1366         int result = 0;
1367
1368         yaffsfs_Lock();
1369         fd = yaffsfs_HandleToFileDes(handle);
1370         obj = yaffsfs_HandleToObject(handle);
1371
1372         if(!fd || !obj)
1373                 /* bad handle */
1374                 yaffsfs_SetError(-EBADF);
1375         else if(!fd->writing)
1376                 yaffsfs_SetError(-EINVAL);
1377         else if(obj->my_dev->read_only)
1378                 yaffsfs_SetError(-EROFS);
1379         else if( new_size < 0 || new_size > YAFFS_MAX_FILE_SIZE)
1380                 yaffsfs_SetError(-EINVAL);
1381         else
1382                 /* resize the file */
1383                 result = yaffs_resize_file(obj, new_size);
1384         yaffsfs_Unlock();
1385
1386         return (result) ? 0 : -1;
1387
1388 }
1389
1390 loff_t yaffs_lseek(int handle, loff_t offset, int whence)
1391 {
1392         yaffsfs_FileDes *fd = NULL;
1393         struct yaffs_obj *obj = NULL;
1394         loff_t pos = -1;
1395         loff_t fSize = -1;
1396
1397         yaffsfs_Lock();
1398         fd = yaffsfs_HandleToFileDes(handle);
1399         obj = yaffsfs_HandleToObject(handle);
1400
1401         if(!fd || !obj)
1402                 yaffsfs_SetError(-EBADF);
1403         else if(offset > YAFFS_MAX_FILE_SIZE)
1404                 yaffsfs_SetError(-EINVAL);
1405         else {
1406                 if(whence == SEEK_SET){
1407                         if(offset >= 0)
1408                                 pos = offset;
1409                 } else if(whence == SEEK_CUR) {
1410                         if( (fd->position + offset) >= 0)
1411                                 pos = (fd->position + offset);
1412                 } else if(whence == SEEK_END) {
1413                         fSize = yaffs_get_obj_length(obj);
1414                         if(fSize >= 0 && (fSize + offset) >= 0)
1415                                 pos = fSize + offset;
1416                 }
1417
1418                 if(pos >= 0 && pos <= YAFFS_MAX_FILE_SIZE)
1419                         fd->position = pos;
1420                 else{
1421                         yaffsfs_SetError(-EINVAL);
1422                         pos = -1;
1423                 }
1424         }
1425
1426         yaffsfs_Unlock();
1427
1428         return pos;
1429 }
1430
1431
1432 int yaffsfs_DoUnlink(const YCHAR *path,int isDirectory)
1433 {
1434         struct yaffs_obj *dir = NULL;
1435         struct yaffs_obj *obj = NULL;
1436         YCHAR *name;
1437         int result = YAFFS_FAIL;
1438         int notDir = 0;
1439         int loop = 0;
1440
1441         if(!path){
1442                 yaffsfs_SetError(-EFAULT);
1443                 return -1;
1444         }
1445
1446         if(yaffsfs_CheckPath(path) < 0){
1447                 yaffsfs_SetError(-ENAMETOOLONG);
1448                 return -1;
1449         }
1450
1451         yaffsfs_Lock();
1452
1453         obj = yaffsfs_FindObject(NULL,path,0,0,NULL,NULL,NULL);
1454         dir = yaffsfs_FindDirectory(NULL,path,&name,0,&notDir,&loop);
1455
1456         if(!dir && notDir)
1457                 yaffsfs_SetError(-ENOTDIR);
1458         else if(loop)
1459                 yaffsfs_SetError(-ELOOP);
1460         else if(!dir)
1461                 yaffsfs_SetError(-ENOENT);
1462         else if(yaffs_strncmp(name,_Y("."),2) == 0)
1463                 yaffsfs_SetError(-EINVAL);
1464         else if(!obj)
1465                 yaffsfs_SetError(-ENOENT);
1466         else if(obj->my_dev->read_only)
1467                 yaffsfs_SetError(-EROFS);
1468         else if(!isDirectory && obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY)
1469                 yaffsfs_SetError(-EISDIR);
1470         else if(isDirectory && obj->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
1471                 yaffsfs_SetError(-ENOTDIR);
1472         else if(isDirectory && obj == obj->my_dev->root_dir)
1473                 yaffsfs_SetError(-EBUSY); /* Can't rmdir a root */
1474         else {
1475                 result = yaffs_unlinker(dir,name);
1476
1477                 if(result == YAFFS_FAIL && isDirectory)
1478                         yaffsfs_SetError(-ENOTEMPTY);
1479         }
1480
1481         yaffsfs_Unlock();
1482
1483         return (result == YAFFS_FAIL) ? -1 : 0;
1484 }
1485
1486
1487 int yaffs_unlink(const YCHAR *path)
1488 {
1489         return yaffsfs_DoUnlink(path,0);
1490 }
1491
1492 int yaffs_rename(const YCHAR *oldPath, const YCHAR *newPath)
1493 {
1494         struct yaffs_obj *olddir = NULL;
1495         struct yaffs_obj *newdir = NULL;
1496         struct yaffs_obj *obj = NULL;
1497         struct yaffs_obj *newobj = NULL;
1498         YCHAR *oldname;
1499         YCHAR *newname;
1500         int result= YAFFS_FAIL;
1501         int rename_allowed = 1;
1502         int notOldDir = 0;
1503         int notNewDir = 0;
1504         int oldLoop = 0;
1505         int newLoop = 0;
1506
1507         YCHAR *alt_newpath=NULL;
1508
1509         if(!oldPath || !newPath){
1510                 yaffsfs_SetError(-EFAULT);
1511                 return -1;
1512         }
1513
1514         if(yaffsfs_CheckPath(oldPath) < 0 ||
1515                 yaffsfs_CheckPath(newPath) < 0){
1516                 yaffsfs_SetError(-ENAMETOOLONG);
1517                 return -1;
1518         }
1519
1520         if(yaffsfs_alt_dir_path(newPath, &alt_newpath) < 0){
1521                 yaffsfs_SetError(-ENOMEM);
1522                 return -1;
1523         }
1524         if(alt_newpath)
1525                 newPath = alt_newpath;
1526
1527         yaffsfs_Lock();
1528
1529
1530         olddir = yaffsfs_FindDirectory(NULL,oldPath,&oldname,0,&notOldDir,&oldLoop);
1531         newdir = yaffsfs_FindDirectory(NULL,newPath,&newname,0,&notNewDir,&newLoop);
1532         obj = yaffsfs_FindObject(NULL,oldPath,0,0,NULL,NULL,NULL);
1533         newobj = yaffsfs_FindObject(NULL,newPath,0,0,NULL,NULL,NULL);
1534
1535         /* If the object being renamed is a directory and the
1536          * path ended with a "/" then the olddir == obj.
1537          * We pass through NULL for the old name to tell the lower layers
1538          * to use olddir as the object.
1539          */
1540
1541         if(olddir == obj)
1542                 oldname = NULL;
1543
1544         if((!olddir && notOldDir) || (!newdir && notNewDir)) {
1545                 yaffsfs_SetError(-ENOTDIR);
1546                 rename_allowed = 0;
1547         } else if(oldLoop || newLoop) {
1548                 yaffsfs_SetError(-ELOOP);
1549                 rename_allowed = 0;
1550         } else if (olddir && oldname && yaffs_strncmp(oldname, _Y("."),2) == 0){
1551                 yaffsfs_SetError(-EINVAL);
1552                 rename_allowed = 0;
1553         }else if(!olddir || !newdir || !obj) {
1554                 yaffsfs_SetError(-ENOENT);
1555                 rename_allowed = 0;
1556         } else if(obj->my_dev->read_only){
1557                 yaffsfs_SetError(-EROFS);
1558                 rename_allowed = 0;
1559         } else if(yaffs_is_non_empty_dir(newobj)){
1560                 yaffsfs_SetError(-ENOTEMPTY);
1561                 rename_allowed = 0;
1562         } else if(olddir->my_dev != newdir->my_dev) {
1563                 /* Rename must be on same device */
1564                 yaffsfs_SetError(-EXDEV);
1565                 rename_allowed = 0;
1566         } else if(obj && obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) {
1567                 /*
1568                  * It is a directory, check that it is not being renamed to
1569                  * being its own decendent.
1570                  * Do this by tracing from the new directory back to the root,
1571                  * checking for obj
1572                  */
1573
1574                 struct yaffs_obj *xx = newdir;
1575
1576                 while( rename_allowed && xx){
1577                         if(xx == obj)
1578                                 rename_allowed = 0;
1579                         xx = xx->parent;
1580                 }
1581                 if(!rename_allowed)
1582                         yaffsfs_SetError(-EINVAL);
1583         }
1584
1585         if(rename_allowed)
1586                 result = yaffs_rename_obj(olddir,oldname,newdir,newname);
1587
1588         yaffsfs_Unlock();
1589
1590         if(alt_newpath)
1591                 kfree(alt_newpath);
1592
1593         return (result == YAFFS_FAIL) ? -1 : 0;
1594 }
1595
1596
1597 static int yaffsfs_DoStat(struct yaffs_obj *obj,struct yaffs_stat *buf)
1598 {
1599         int retVal = -1;
1600
1601         obj = yaffs_get_equivalent_obj(obj);
1602
1603         if(obj && buf){
1604                 buf->st_dev = (int)obj->my_dev->os_context;
1605                 buf->st_ino = obj->obj_id;
1606                 buf->st_mode = obj->yst_mode & ~S_IFMT; /* clear out file type bits */
1607
1608                 if(obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY)
1609                         buf->st_mode |= S_IFDIR;
1610                 else if(obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK)
1611                         buf->st_mode |= S_IFLNK;
1612                 else if(obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
1613                         buf->st_mode |= S_IFREG;
1614
1615                 buf->st_nlink = yaffs_get_obj_link_count(obj);
1616                 buf->st_uid = 0;
1617                 buf->st_gid = 0;;
1618                 buf->st_rdev = obj->yst_rdev;
1619                 buf->st_size = yaffs_get_obj_length(obj);
1620                 buf->st_blksize = obj->my_dev->data_bytes_per_chunk;
1621                 buf->st_blocks = (buf->st_size + buf->st_blksize -1)/buf->st_blksize;
1622 #if CONFIG_YAFFS_WINCE
1623                 buf->yst_wince_atime[0] = obj->win_atime[0];
1624                 buf->yst_wince_atime[1] = obj->win_atime[1];
1625                 buf->yst_wince_ctime[0] = obj->win_ctime[0];
1626                 buf->yst_wince_ctime[1] = obj->win_ctime[1];
1627                 buf->yst_wince_mtime[0] = obj->win_mtime[0];
1628                 buf->yst_wince_mtime[1] = obj->win_mtime[1];
1629 #else
1630                 buf->yst_atime = obj->yst_atime;
1631                 buf->yst_ctime = obj->yst_ctime;
1632                 buf->yst_mtime = obj->yst_mtime;
1633 #endif
1634                 retVal = 0;
1635         }
1636         return retVal;
1637 }
1638
1639 static int yaffsfs_DoStatOrLStat(const YCHAR *path, struct yaffs_stat *buf,int doLStat)
1640 {
1641         struct yaffs_obj *obj=NULL;
1642         struct yaffs_obj *dir=NULL;
1643         int retVal = -1;
1644         int notDir = 0;
1645         int loop = 0;
1646
1647         if(!path || !buf){
1648                 yaffsfs_SetError(-EFAULT);
1649                 return -1;
1650         }
1651
1652         if(yaffsfs_CheckPath(path) < 0){
1653                 yaffsfs_SetError(-ENAMETOOLONG);
1654                 return -1;
1655         }
1656
1657         yaffsfs_Lock();
1658
1659         obj = yaffsfs_FindObject(NULL,path,0,1,&dir,&notDir,&loop);
1660
1661         if(!doLStat && obj)
1662                 obj = yaffsfs_FollowLink(obj,0,&loop);
1663
1664         if(!dir && notDir)
1665                 yaffsfs_SetError(-ENOTDIR);
1666         else if(loop)
1667                 yaffsfs_SetError(-ELOOP);
1668         else if(!dir || !obj)
1669                 yaffsfs_SetError(-ENOENT);
1670         else
1671                 retVal = yaffsfs_DoStat(obj,buf);
1672
1673         yaffsfs_Unlock();
1674
1675         return retVal;
1676
1677 }
1678
1679 int yaffs_stat(const YCHAR *path, struct yaffs_stat *buf)
1680 {
1681         return yaffsfs_DoStatOrLStat(path,buf,0);
1682 }
1683
1684 int yaffs_lstat(const YCHAR *path, struct yaffs_stat *buf)
1685 {
1686         return yaffsfs_DoStatOrLStat(path,buf,1);
1687 }
1688
1689 int yaffs_fstat(int fd, struct yaffs_stat *buf)
1690 {
1691         struct yaffs_obj *obj;
1692
1693         int retVal = -1;
1694
1695         if(!buf){
1696                 yaffsfs_SetError(-EFAULT);
1697                 return -1;
1698         }
1699
1700         yaffsfs_Lock();
1701         obj = yaffsfs_HandleToObject(fd);
1702
1703         if(obj)
1704                 retVal = yaffsfs_DoStat(obj,buf);
1705         else
1706                 /* bad handle */
1707                 yaffsfs_SetError(-EBADF);
1708
1709         yaffsfs_Unlock();
1710
1711         return retVal;
1712 }
1713
1714 static int yaffsfs_DoUtime(struct yaffs_obj *obj,const struct yaffs_utimbuf *buf)
1715 {
1716         int retVal = -1;
1717         int result;
1718
1719         struct yaffs_utimbuf local;
1720
1721         obj = yaffs_get_equivalent_obj(obj);
1722
1723         if(obj && obj->my_dev->read_only) {
1724                 yaffsfs_SetError(-EROFS);
1725                 return -1;
1726         }
1727
1728
1729         if(!buf){
1730                 local.actime = Y_CURRENT_TIME;
1731                 local.modtime = local.actime;
1732                 buf = &local;
1733         }
1734
1735         if(obj){
1736                 obj->yst_atime = buf->actime;
1737                 obj->yst_mtime = buf->modtime;
1738                 obj->dirty = 1;
1739                 result = yaffs_flush_file(obj,0,0);
1740                 retVal = result == YAFFS_OK ? 0 : -1;
1741         }
1742
1743         return retVal;
1744 }
1745
1746 int yaffs_utime(const YCHAR *path, const struct yaffs_utimbuf *buf)
1747 {
1748         struct yaffs_obj *obj=NULL;
1749         struct yaffs_obj *dir=NULL;
1750         int retVal = -1;
1751         int notDir = 0;
1752         int loop = 0;
1753
1754         if(!path){
1755                 yaffsfs_SetError(-EFAULT);
1756                 return -1;
1757         }
1758
1759         if(yaffsfs_CheckPath(path) < 0){
1760                 yaffsfs_SetError(-ENAMETOOLONG);
1761                 return -1;
1762         }
1763
1764         yaffsfs_Lock();
1765
1766         obj = yaffsfs_FindObject(NULL,path,0,1,&dir,&notDir,&loop);
1767
1768         if(!dir && notDir)
1769                 yaffsfs_SetError(-ENOTDIR);
1770         else if(loop)
1771                 yaffsfs_SetError(-ELOOP);
1772         else if(!dir || !obj)
1773                 yaffsfs_SetError(-ENOENT);
1774         else
1775                 retVal = yaffsfs_DoUtime(obj,buf);
1776
1777         yaffsfs_Unlock();
1778
1779         return retVal;
1780
1781 }
1782 int yaffs_futime(int fd, const struct yaffs_utimbuf *buf)
1783 {
1784         struct yaffs_obj *obj;
1785
1786         int retVal = -1;
1787
1788         yaffsfs_Lock();
1789         obj = yaffsfs_HandleToObject(fd);
1790
1791         if(obj)
1792                 retVal = yaffsfs_DoUtime(obj,buf);
1793         else
1794                 /* bad handle */
1795                 yaffsfs_SetError(-EBADF);
1796
1797         yaffsfs_Unlock();
1798
1799         return retVal;
1800 }
1801
1802
1803 #ifndef CONFIG_YAFFS_WINCE
1804 /* xattrib functions */
1805
1806
1807 static int yaffs_do_setxattr(const YCHAR *path, const char *name,
1808                         const void *data, int size, int flags, int follow)
1809 {
1810         struct yaffs_obj *obj;
1811         struct yaffs_obj *dir;
1812         int notDir = 0;
1813         int loop = 0;
1814
1815         int retVal = -1;
1816
1817         if(!path || !name || !data){
1818                 yaffsfs_SetError(-EFAULT);
1819                 return -1;
1820         }
1821
1822         if(yaffsfs_CheckPath(path) < 0){
1823                 yaffsfs_SetError(-ENAMETOOLONG);
1824                 return -1;
1825         }
1826
1827         yaffsfs_Lock();
1828
1829         obj = yaffsfs_FindObject(NULL,path,0,1,&dir,&notDir,&loop);
1830
1831         if(follow)
1832                 obj = yaffsfs_FollowLink(obj,0,&loop);
1833
1834         if(!dir && notDir)
1835                 yaffsfs_SetError(-ENOTDIR);
1836         else if(loop)
1837                 yaffsfs_SetError(-ELOOP);
1838         else if(!dir || !obj)
1839                 yaffsfs_SetError(-ENOENT);
1840         else {
1841                 retVal = yaffs_set_xattrib(obj,name,data,size,flags);
1842                 if(retVal< 0){
1843                         yaffsfs_SetError(retVal);
1844                         retVal = -1;
1845                 }
1846         }
1847
1848         yaffsfs_Unlock();
1849
1850         return retVal;
1851
1852 }
1853
1854 int yaffs_setxattr(const YCHAR *path, const char *name, const void *data, int size, int flags)
1855 {
1856         return yaffs_do_setxattr(path, name, data, size, flags, 1);
1857 }
1858
1859 int yaffs_lsetxattr(const YCHAR *path, const char *name, const void *data, int size, int flags)
1860 {
1861         return yaffs_do_setxattr(path, name, data, size, flags, 0);
1862 }
1863
1864
1865
1866 int yaffs_fsetxattr(int fd, const char *name, const void *data, int size, int flags)
1867 {
1868         struct yaffs_obj *obj;
1869
1870         int retVal = -1;
1871
1872         if(!name || !data){
1873                 yaffsfs_SetError(-EFAULT);
1874                 return -1;
1875         }
1876
1877         yaffsfs_Lock();
1878         obj = yaffsfs_HandleToObject(fd);
1879
1880         if(!obj)
1881                 yaffsfs_SetError(-EBADF);
1882         else {
1883                 retVal = yaffs_set_xattrib(obj,name,data,size,flags);
1884                 if(retVal< 0){
1885                         yaffsfs_SetError(retVal);
1886                         retVal = -1;
1887                 }
1888         }
1889
1890         yaffsfs_Unlock();
1891
1892         return retVal;
1893 }
1894
1895 static int yaffs_do_getxattr(const YCHAR *path, const char *name, void *data, int size, int follow)
1896 {
1897         struct yaffs_obj *obj;
1898         struct yaffs_obj *dir;
1899         int retVal = -1;
1900         int notDir = 0;
1901         int loop = 0;
1902
1903         if(!path || !name || !data ){
1904                 yaffsfs_SetError(-EFAULT);
1905                 return -1;
1906         }
1907
1908         if(yaffsfs_CheckPath(path) < 0){
1909                 yaffsfs_SetError(-ENAMETOOLONG);
1910                 return -1;
1911         }
1912
1913         yaffsfs_Lock();
1914
1915         obj = yaffsfs_FindObject(NULL,path,0,1,&dir,&notDir,&loop);
1916
1917         if(follow)
1918                 obj = yaffsfs_FollowLink(obj,0,&loop);
1919
1920         if(!dir && notDir)
1921                 yaffsfs_SetError(-ENOTDIR);
1922         else if(loop)
1923                 yaffsfs_SetError(-ELOOP);
1924         else if(!dir || !obj)
1925                 yaffsfs_SetError(-ENOENT);
1926         else {
1927                 retVal = yaffs_get_xattrib(obj,name,data,size);
1928                 if(retVal< 0){
1929                         yaffsfs_SetError(retVal);
1930                         retVal = -1;
1931                 }
1932         }
1933         yaffsfs_Unlock();
1934
1935         return retVal;
1936
1937 }
1938
1939 int yaffs_getxattr(const YCHAR *path, const char *name, void *data, int size)
1940 {
1941         return yaffs_do_getxattr( path, name, data, size, 1);
1942 }
1943 int yaffs_lgetxattr(const YCHAR *path, const char *name, void *data, int size)
1944 {
1945         return yaffs_do_getxattr( path, name, data, size, 0);
1946 }
1947
1948
1949
1950 int yaffs_fgetxattr(int fd, const char *name, void *data, int size)
1951 {
1952         struct yaffs_obj *obj;
1953
1954         int retVal = -1;
1955
1956         if(!name || !data ){
1957                 yaffsfs_SetError(-EFAULT);
1958                 return -1;
1959         }
1960
1961         yaffsfs_Lock();
1962         obj = yaffsfs_HandleToObject(fd);
1963
1964         if(obj) {
1965                 retVal = yaffs_get_xattrib(obj,name,data,size);
1966                 if(retVal< 0){
1967                         yaffsfs_SetError(retVal);
1968                         retVal = -1;
1969                 }
1970         } else
1971                 /* bad handle */
1972                 yaffsfs_SetError(-EBADF);
1973
1974         yaffsfs_Unlock();
1975
1976         return retVal;
1977 }
1978
1979 static int yaffs_do_listxattr(const YCHAR *path, char *data, int size, int follow)
1980 {
1981         struct yaffs_obj *obj=NULL;
1982         struct yaffs_obj *dir=NULL;
1983         int retVal = -1;
1984         int notDir = 0;
1985         int loop = 0;
1986
1987         if(!path || !data ){
1988                 yaffsfs_SetError(-EFAULT);
1989                 return -1;
1990         }
1991
1992         if(yaffsfs_CheckPath(path) < 0){
1993                 yaffsfs_SetError(-ENAMETOOLONG);
1994                 return -1;
1995         }
1996
1997         yaffsfs_Lock();
1998
1999         obj = yaffsfs_FindObject(NULL,path,0,1,&dir,&notDir,&loop);
2000
2001         if(follow)
2002                 obj = yaffsfs_FollowLink(obj,0,&loop);
2003
2004         if(!dir && notDir)
2005                 yaffsfs_SetError(-ENOTDIR);
2006         else if(loop)
2007                 yaffsfs_SetError(-ELOOP);
2008         else if(!dir || !obj)
2009                 yaffsfs_SetError(-ENOENT);
2010         else {
2011                 retVal = yaffs_list_xattrib(obj, data,size);
2012                 if(retVal< 0){
2013                         yaffsfs_SetError(retVal);
2014                         retVal = -1;
2015                 }
2016         }
2017
2018         yaffsfs_Unlock();
2019
2020         return retVal;
2021
2022 }
2023
2024 int yaffs_listxattr(const YCHAR *path, char *data, int size)
2025 {
2026         return yaffs_do_listxattr(path, data, size, 1);
2027 }
2028
2029 int yaffs_llistxattr(const YCHAR *path, char *data, int size)
2030 {
2031         return yaffs_do_listxattr(path, data, size, 0);
2032 }
2033
2034 int yaffs_flistxattr(int fd, char *data, int size)
2035 {
2036         struct yaffs_obj *obj;
2037
2038         int retVal = -1;
2039
2040         if(!data ){
2041                 yaffsfs_SetError(-EFAULT);
2042                 return -1;
2043         }
2044
2045         yaffsfs_Lock();
2046         obj = yaffsfs_HandleToObject(fd);
2047
2048         if(obj) {
2049                 retVal = yaffs_list_xattrib(obj,data,size);
2050                 if(retVal< 0){
2051                         yaffsfs_SetError(retVal);
2052                         retVal = -1;
2053                 }
2054         } else
2055                 /* bad handle */
2056                 yaffsfs_SetError(-EBADF);
2057
2058         yaffsfs_Unlock();
2059
2060         return retVal;
2061 }
2062
2063 static int yaffs_do_removexattr(const YCHAR *path, const char *name, int follow)
2064 {
2065         struct yaffs_obj *obj=NULL;
2066         struct yaffs_obj *dir=NULL;
2067         int notDir = 0;
2068         int loop = 0;
2069         int retVal = -1;
2070
2071         if(!path || !name){
2072                 yaffsfs_SetError(-EFAULT);
2073                 return -1;
2074         }
2075
2076         if(yaffsfs_CheckPath(path) < 0){
2077                 yaffsfs_SetError(-ENAMETOOLONG);
2078                 return -1;
2079         }
2080
2081         yaffsfs_Lock();
2082
2083         obj = yaffsfs_FindObject(NULL,path,0,1, &dir,&notDir,&loop);
2084
2085         if(follow)
2086                 obj = yaffsfs_FollowLink(obj,0,&loop);
2087
2088         if(!dir && notDir)
2089                 yaffsfs_SetError(-ENOTDIR);
2090         else if(loop)
2091                 yaffsfs_SetError(-ELOOP);
2092         else if(!dir || !obj)
2093                 yaffsfs_SetError(-ENOENT);
2094         else {
2095                 retVal = yaffs_remove_xattrib(obj,name);
2096                 if(retVal< 0){
2097                         yaffsfs_SetError(retVal);
2098                         retVal = -1;
2099                 }
2100         }
2101
2102         yaffsfs_Unlock();
2103
2104         return retVal;
2105
2106 }
2107
2108 int yaffs_removexattr(const YCHAR *path, const char *name)
2109 {
2110         return yaffs_do_removexattr(path, name, 1);
2111 }
2112
2113 int yaffs_lremovexattr(const YCHAR *path, const char *name)
2114 {
2115         return yaffs_do_removexattr(path, name, 0);
2116 }
2117
2118 int yaffs_fremovexattr(int fd, const char *name)
2119 {
2120         struct yaffs_obj *obj;
2121
2122         int retVal = -1;
2123
2124         if(!name){
2125                 yaffsfs_SetError(-EFAULT);
2126                 return -1;
2127         }
2128
2129         yaffsfs_Lock();
2130         obj = yaffsfs_HandleToObject(fd);
2131
2132         if(obj){
2133                 retVal = yaffs_remove_xattrib(obj,name);
2134                 if(retVal< 0){
2135                         yaffsfs_SetError(retVal);
2136                         retVal = -1;
2137                 }
2138         }else
2139                 /* bad handle */
2140                 yaffsfs_SetError(-EBADF);
2141
2142         yaffsfs_Unlock();
2143
2144         return retVal;
2145 }
2146 #endif
2147
2148 #ifdef CONFIG_YAFFS_WINCE
2149 int yaffs_get_wince_times(int fd, unsigned *wctime, unsigned *watime, unsigned *wmtime)
2150 {
2151         struct yaffs_obj *obj;
2152
2153         int retVal = -1;
2154
2155         yaffsfs_Lock();
2156         obj = yaffsfs_HandleToObject(fd);
2157
2158         if(obj){
2159
2160                 if(wctime){
2161                         wctime[0] = obj->win_ctime[0];
2162                         wctime[1] = obj->win_ctime[1];
2163                 }
2164                 if(watime){
2165                         watime[0] = obj->win_atime[0];
2166                         watime[1] = obj->win_atime[1];
2167                 }
2168                 if(wmtime){
2169                         wmtime[0] = obj->win_mtime[0];
2170                         wmtime[1] = obj->win_mtime[1];
2171                 }
2172
2173
2174                 retVal = 0;
2175         } else
2176                 /*  bad handle */
2177                 yaffsfs_SetError(-EBADF);
2178
2179         yaffsfs_Unlock();
2180
2181         return retVal;
2182 }
2183
2184
2185 int yaffs_set_wince_times(int fd,
2186                                                   const unsigned *wctime,
2187                                                   const unsigned *watime,
2188                                                   const unsigned *wmtime)
2189 {
2190         struct yaffs_obj *obj;
2191         int result;
2192         int retVal = -1;
2193
2194         yaffsfs_Lock();
2195         obj = yaffsfs_HandleToObject(fd);
2196
2197         if(obj){
2198
2199                 if(wctime){
2200                         obj->win_ctime[0] = wctime[0];
2201                         obj->win_ctime[1] = wctime[1];
2202                 }
2203                 if(watime){
2204                         obj->win_atime[0] = watime[0];
2205                         obj->win_atime[1] = watime[1];
2206                 }
2207                 if(wmtime){
2208                         obj->win_mtime[0] = wmtime[0];
2209                         obj->win_mtime[1] = wmtime[1];
2210                 }
2211
2212                 obj->dirty = 1;
2213                 result = yaffs_flush_file(obj,0,0);
2214                 retVal = 0;
2215         } else
2216                 /* bad handle */
2217                 yaffsfs_SetError(-EBADF);
2218
2219         yaffsfs_Unlock();
2220
2221         return retVal;
2222 }
2223
2224 #endif
2225
2226
2227 static int yaffsfs_DoChMod(struct yaffs_obj *obj,mode_t mode)
2228 {
2229         int result = -1;
2230
2231         if(obj)
2232                 obj = yaffs_get_equivalent_obj(obj);
2233
2234         if(obj) {
2235                 obj->yst_mode = mode;
2236                 obj->dirty = 1;
2237                 result = yaffs_flush_file(obj,0,0);
2238         }
2239
2240         return result == YAFFS_OK ? 0 : -1;
2241 }
2242
2243
2244 int yaffs_access(const YCHAR *path, int amode)
2245 {
2246         struct yaffs_obj *obj=NULL;
2247         struct yaffs_obj *dir=NULL;
2248         int notDir = 0;
2249         int loop = 0;
2250         int retval = -1;
2251
2252         if(!path){
2253                 yaffsfs_SetError(-EFAULT);
2254                 return -1;
2255         }
2256
2257         if(yaffsfs_CheckPath(path) < 0){
2258                 yaffsfs_SetError(-ENAMETOOLONG);
2259                 return -1;
2260         }
2261
2262         if(amode & ~(R_OK | W_OK | X_OK)){
2263                 yaffsfs_SetError(-EINVAL);
2264                 return -1;
2265         }
2266
2267         yaffsfs_Lock();
2268
2269         obj = yaffsfs_FindObject(NULL,path,0,1, &dir,&notDir,&loop);
2270         obj = yaffsfs_FollowLink(obj,0,&loop);
2271
2272         if(!dir && notDir)
2273                 yaffsfs_SetError(-ENOTDIR);
2274         else if(loop)
2275                 yaffsfs_SetError(-ELOOP);
2276         else if(!dir || !obj)
2277                 yaffsfs_SetError(-ENOENT);
2278         else if((amode & W_OK) && obj->my_dev->read_only)
2279                 yaffsfs_SetError(-EROFS);
2280         else{
2281                 int access_ok = 1;
2282
2283                 if((amode & R_OK) && !(obj->yst_mode & S_IREAD))
2284                         access_ok = 0;
2285                 if((amode & W_OK) && !(obj->yst_mode & S_IWRITE))
2286                         access_ok = 0;
2287                 if((amode & X_OK) && !(obj->yst_mode & S_IEXEC))
2288                         access_ok = 0;
2289
2290                 if(!access_ok)
2291                         yaffsfs_SetError(-EACCES);
2292                 else
2293                         retval = 0;
2294         }
2295
2296         yaffsfs_Unlock();
2297
2298         return retval;
2299
2300 }
2301
2302
2303 int yaffs_chmod(const YCHAR *path, mode_t mode)
2304 {
2305         struct yaffs_obj *obj=NULL;
2306         struct yaffs_obj *dir=NULL;
2307         int retVal = -1;
2308         int notDir = 0;
2309         int loop = 0;
2310
2311         if(!path){
2312                 yaffsfs_SetError(-EFAULT);
2313                 return -1;
2314         }
2315
2316         if(yaffsfs_CheckPath(path) < 0){
2317                 yaffsfs_SetError(-ENAMETOOLONG);
2318                 return -1;
2319         }
2320
2321         if(mode & ~(0777)){
2322                 yaffsfs_SetError(-EINVAL);
2323                 return -1;
2324         }
2325
2326         yaffsfs_Lock();
2327
2328         obj = yaffsfs_FindObject(NULL,path,0,1, &dir, &notDir,&loop);
2329         obj = yaffsfs_FollowLink(obj,0,&loop);
2330
2331         if(!dir && notDir)
2332                 yaffsfs_SetError(-ENOTDIR);
2333         else if(loop)
2334                 yaffsfs_SetError(-ELOOP);
2335         else if(!dir || !obj)
2336                 yaffsfs_SetError(-ENOENT);
2337         else if(obj->my_dev->read_only)
2338                 yaffsfs_SetError(-EROFS);
2339         else
2340                 retVal = yaffsfs_DoChMod(obj,mode);
2341
2342         yaffsfs_Unlock();
2343
2344         return retVal;
2345
2346 }
2347
2348
2349 int yaffs_fchmod(int fd, mode_t mode)
2350 {
2351         struct yaffs_obj *obj;
2352         int retVal = -1;
2353
2354         if(mode & ~(0777)){
2355                 yaffsfs_SetError(-EINVAL);
2356                 return -1;
2357         }
2358
2359         yaffsfs_Lock();
2360         obj = yaffsfs_HandleToObject(fd);
2361
2362         if(!obj)
2363                 yaffsfs_SetError(-EBADF);
2364         else if(obj->my_dev->read_only)
2365                 yaffsfs_SetError(-EROFS);
2366         else
2367                 retVal = yaffsfs_DoChMod(obj,mode);
2368
2369         yaffsfs_Unlock();
2370
2371         return retVal;
2372 }
2373
2374 int yaffs_mkdir(const YCHAR *path, mode_t mode)
2375 {
2376         struct yaffs_obj *parent = NULL;
2377         struct yaffs_obj *dir = NULL;
2378         YCHAR *name;
2379         YCHAR *alt_path = NULL;
2380         int retVal= -1;
2381         int notDir = 0;
2382         int loop = 0;
2383
2384         if(!path){
2385                 yaffsfs_SetError(-EFAULT);
2386                 return -1;
2387         }
2388
2389         if(yaffsfs_CheckPath(path) < 0){
2390                 yaffsfs_SetError(-ENAMETOOLONG);
2391                 return -1;
2392         }
2393
2394         if(yaffsfs_alt_dir_path(path, &alt_path) < 0){
2395                 yaffsfs_SetError(-ENOMEM);
2396                 return -1;
2397         }
2398         if(alt_path)
2399                 path = alt_path;
2400
2401         yaffsfs_Lock();
2402         parent = yaffsfs_FindDirectory(NULL,path,&name,0,&notDir,&loop);
2403         if(!parent && notDir)
2404                 yaffsfs_SetError(-ENOTDIR);
2405         else if(loop)
2406                 yaffsfs_SetError(-ELOOP);
2407         else if(!parent)
2408                 yaffsfs_SetError(-ENOENT);
2409         else if(yaffsfs_TooManyObjects(parent->my_dev))
2410                 yaffsfs_SetError(-ENFILE);
2411         else if(yaffs_strnlen(name,5) == 0){
2412                 /* Trying to make the root itself */
2413                 yaffsfs_SetError(-EEXIST);
2414         } else if(parent->my_dev->read_only)
2415                 yaffsfs_SetError(-EROFS);
2416         else {
2417                 dir = yaffs_create_dir(parent,name,mode,0,0);
2418                 if(dir)
2419                         retVal = 0;
2420                 else if (yaffs_find_by_name(parent,name))
2421                         yaffsfs_SetError(-EEXIST); /* the name already exists */
2422                 else
2423                         yaffsfs_SetError(-ENOSPC); /* just assume no space */
2424         }
2425
2426         yaffsfs_Unlock();
2427
2428         if(alt_path)
2429                 kfree(alt_path);
2430
2431         return retVal;
2432 }
2433
2434 int yaffs_rmdir(const YCHAR *path)
2435 {
2436         int result;
2437         YCHAR *alt_path;
2438
2439         if(!path){
2440                 yaffsfs_SetError(-EFAULT);
2441                 return -1;
2442         }
2443
2444         if(yaffsfs_CheckPath(path) < 0){
2445                 yaffsfs_SetError(-ENAMETOOLONG);
2446                 return -1;
2447         }
2448
2449         if(yaffsfs_alt_dir_path(path, &alt_path) < 0){
2450                 yaffsfs_SetError(-ENOMEM);
2451                 return -1;
2452         }
2453         if(alt_path)
2454                 path = alt_path;
2455         result =  yaffsfs_DoUnlink(path,1);
2456         if(alt_path)
2457                 kfree(alt_path);
2458         return result;
2459 }
2460
2461
2462 void * yaffs_getdev(const YCHAR *path)
2463 {
2464         struct yaffs_dev *dev=NULL;
2465         YCHAR *dummy;
2466         dev = yaffsfs_FindDevice(path,&dummy);
2467         return (void *)dev;
2468 }
2469
2470 int yaffs_mount_common(const YCHAR *path,int read_only, int skip_checkpt)
2471 {
2472         int retVal=-1;
2473         int result=YAFFS_FAIL;
2474         struct yaffs_dev *dev=NULL;
2475
2476         if(!path){
2477                 yaffsfs_SetError(-EFAULT);
2478                 return -1;
2479         }
2480
2481         yaffs_trace(YAFFS_TRACE_MOUNT,"yaffs: Mounting %s",path);
2482
2483         if(yaffsfs_CheckPath(path) < 0){
2484                 yaffsfs_SetError(-ENAMETOOLONG);
2485                 return -1;
2486         }
2487
2488         yaffsfs_Lock();
2489
2490         yaffsfs_InitHandles();
2491
2492         dev = yaffsfs_FindMountPoint(path);
2493         if(dev){
2494                 if(!dev->is_mounted){
2495                         dev->read_only = read_only ? 1 : 0;
2496                         if(skip_checkpt) {
2497                                 u8 skip = dev->param.skip_checkpt_rd;
2498                                 dev->param.skip_checkpt_rd = 1;
2499                                 result = yaffs_guts_initialise(dev);
2500                                 dev->param.skip_checkpt_rd = skip;
2501                         } else {
2502                                 result = yaffs_guts_initialise(dev);
2503                         }
2504
2505                         if(result == YAFFS_FAIL)
2506                                 yaffsfs_SetError(-ENOMEM);
2507                         retVal = result ? 0 : -1;
2508
2509                 }
2510                 else
2511                         yaffsfs_SetError(-EBUSY);
2512         } else
2513                 yaffsfs_SetError(-ENODEV);
2514
2515         yaffsfs_Unlock();
2516         return retVal;
2517
2518 }
2519
2520 int yaffs_mount2(const YCHAR *path, int readonly)
2521 {
2522         return yaffs_mount_common(path, readonly, 0);
2523 }
2524 int yaffs_mount(const YCHAR *path)
2525 {
2526         return yaffs_mount_common(path, 0, 0);
2527 }
2528
2529 int yaffs_sync(const YCHAR *path)
2530 {
2531         int retVal=-1;
2532         struct yaffs_dev *dev=NULL;
2533         YCHAR *dummy;
2534
2535         if(!path){
2536                 yaffsfs_SetError(-EFAULT);
2537                 return -1;
2538         }
2539
2540         if(yaffsfs_CheckPath(path) < 0){
2541                 yaffsfs_SetError(-ENAMETOOLONG);
2542                 return -1;
2543         }
2544
2545         yaffsfs_Lock();
2546         dev = yaffsfs_FindDevice(path,&dummy);
2547         if(dev){
2548                 if(!dev->is_mounted)
2549                         yaffsfs_SetError(-EINVAL);
2550                 else if(dev->read_only)
2551                         yaffsfs_SetError(-EROFS);
2552                 else {
2553
2554                         yaffs_flush_whole_cache(dev);
2555                         yaffs_checkpoint_save(dev);
2556                         retVal = 0;
2557
2558                 }
2559         }else
2560                 yaffsfs_SetError(-ENODEV);
2561
2562         yaffsfs_Unlock();
2563         return retVal;
2564 }
2565
2566
2567 static int yaffsfs_IsDevBusy(struct yaffs_dev * dev)
2568 {
2569         int i;
2570         struct yaffs_obj *obj;
2571
2572         for(i = 0; i < YAFFSFS_N_HANDLES; i++){
2573                 obj = yaffsfs_HandleToObject(i);
2574                 if(obj && obj->my_dev == dev)
2575                 return 1;
2576         }
2577         return 0;
2578 }
2579
2580
2581 int yaffs_remount(const YCHAR *path, int force, int read_only)
2582 {
2583         int retVal=-1;
2584         struct yaffs_dev *dev=NULL;
2585
2586         if(!path){
2587                 yaffsfs_SetError(-EFAULT);
2588                 return -1;
2589         }
2590
2591         if(yaffsfs_CheckPath(path) < 0){
2592                 yaffsfs_SetError(-ENAMETOOLONG);
2593                 return -1;
2594         }
2595
2596         yaffsfs_Lock();
2597         dev = yaffsfs_FindMountPoint(path);
2598         if(dev){
2599                 if(dev->is_mounted){
2600                         yaffs_flush_whole_cache(dev);
2601
2602                         if(force || ! yaffsfs_IsDevBusy(dev)){
2603                                 if(read_only)
2604                                         yaffs_checkpoint_save(dev);
2605                                 dev->read_only =  read_only ? 1 : 0;
2606                                 retVal = 0;
2607                         } else
2608                                 yaffsfs_SetError(-EBUSY);
2609
2610                 } else
2611                         yaffsfs_SetError(-EINVAL);
2612
2613         }
2614         else
2615                 yaffsfs_SetError(-ENODEV);
2616
2617         yaffsfs_Unlock();
2618         return retVal;
2619
2620 }
2621
2622 int yaffs_unmount2(const YCHAR *path, int force)
2623 {
2624         int retVal=-1;
2625         struct yaffs_dev *dev=NULL;
2626
2627         if(!path){
2628                 yaffsfs_SetError(-EFAULT);
2629                 return -1;
2630         }
2631
2632         if(yaffsfs_CheckPath(path) < 0){
2633                 yaffsfs_SetError(-ENAMETOOLONG);
2634                 return -1;
2635         }
2636
2637         yaffsfs_Lock();
2638         dev = yaffsfs_FindMountPoint(path);
2639         if(dev){
2640                 if(dev->is_mounted){
2641                         int inUse;
2642                         yaffs_flush_whole_cache(dev);
2643                         yaffs_checkpoint_save(dev);
2644                         inUse = yaffsfs_IsDevBusy(dev);
2645                         if(!inUse || force){
2646                                 if(inUse)
2647                                         yaffsfs_BreakDeviceHandles(dev);
2648                                 yaffs_deinitialise(dev);
2649
2650                                 retVal = 0;
2651                         } else
2652                                 yaffsfs_SetError(-EBUSY);
2653
2654                 } else
2655                         yaffsfs_SetError(-EINVAL);
2656
2657         } else
2658                 yaffsfs_SetError(-ENODEV);
2659
2660         yaffsfs_Unlock();
2661         return retVal;
2662
2663 }
2664
2665 int yaffs_unmount(const YCHAR *path)
2666 {
2667         return yaffs_unmount2(path,0);
2668 }
2669
2670 loff_t yaffs_freespace(const YCHAR *path)
2671 {
2672         loff_t retVal=-1;
2673         struct yaffs_dev *dev=NULL;
2674         YCHAR *dummy;
2675
2676         if(!path){
2677                 yaffsfs_SetError(-EFAULT);
2678                 return -1;
2679         }
2680
2681         if(yaffsfs_CheckPath(path) < 0){
2682                 yaffsfs_SetError(-ENAMETOOLONG);
2683                 return -1;
2684         }
2685
2686         yaffsfs_Lock();
2687         dev = yaffsfs_FindDevice(path,&dummy);
2688         if(dev  && dev->is_mounted){
2689                 retVal = yaffs_get_n_free_chunks(dev);
2690                 retVal *= dev->data_bytes_per_chunk;
2691
2692         } else
2693                 yaffsfs_SetError(-EINVAL);
2694
2695         yaffsfs_Unlock();
2696         return retVal;
2697 }
2698
2699 loff_t yaffs_totalspace(const YCHAR *path)
2700 {
2701         loff_t retVal=-1;
2702         struct yaffs_dev *dev=NULL;
2703         YCHAR *dummy;
2704
2705         if(!path){
2706                 yaffsfs_SetError(-EFAULT);
2707                 return -1;
2708         }
2709
2710         if(yaffsfs_CheckPath(path) < 0){
2711                 yaffsfs_SetError(-ENAMETOOLONG);
2712                 return -1;
2713         }
2714
2715         yaffsfs_Lock();
2716         dev = yaffsfs_FindDevice(path,&dummy);
2717         if(dev  && dev->is_mounted){
2718                 retVal = (dev->param.end_block - dev->param.start_block + 1) -
2719                         dev->param.n_reserved_blocks;
2720                 retVal *= dev->param.chunks_per_block;
2721                 retVal *= dev->data_bytes_per_chunk;
2722
2723         } else
2724                 yaffsfs_SetError(-EINVAL);
2725
2726         yaffsfs_Unlock();
2727         return retVal;
2728 }
2729
2730 int yaffs_inodecount(const YCHAR *path)
2731 {
2732         loff_t retVal= -1;
2733         struct yaffs_dev *dev=NULL;
2734         YCHAR *dummy;
2735
2736         if(!path){
2737                 yaffsfs_SetError(-EFAULT);
2738                 return -1;
2739         }
2740
2741         if(yaffsfs_CheckPath(path) < 0){
2742                 yaffsfs_SetError(-ENAMETOOLONG);
2743                 return -1;
2744         }
2745
2746         yaffsfs_Lock();
2747         dev = yaffsfs_FindDevice(path,&dummy);
2748         if(dev  && dev->is_mounted) {
2749            int n_obj = dev->n_obj;
2750            if(n_obj > dev->n_hardlinks)
2751                 retVal = n_obj - dev->n_hardlinks;
2752         }
2753
2754         if(retVal < 0)
2755                 yaffsfs_SetError(-EINVAL);
2756
2757         yaffsfs_Unlock();
2758         return retVal;
2759 }
2760
2761
2762 void yaffs_add_device(struct yaffs_dev *dev)
2763 {
2764         struct list_head *cfg;
2765         /* First check that the device is not in the list. */
2766
2767         list_for_each(cfg, &yaffsfs_deviceList){
2768                 if(dev == list_entry(cfg, struct yaffs_dev, dev_list))
2769                         return;
2770         }
2771
2772         dev->is_mounted = 0;
2773         dev->param.remove_obj_fn = yaffsfs_RemoveObjectCallback;
2774
2775         if(!dev->dev_list.next)
2776                 INIT_LIST_HEAD(&dev->dev_list);
2777
2778         list_add(&dev->dev_list,&yaffsfs_deviceList);
2779 }
2780
2781 void yaffs_remove_device(struct yaffs_dev *dev)
2782 {
2783         list_del_init(&dev->dev_list);
2784 }
2785
2786 /* Functions to iterate through devices. NB Use with extreme care! */
2787
2788 static struct list_head *dev_iterator;
2789 void yaffs_dev_rewind(void)
2790 {
2791         dev_iterator = yaffsfs_deviceList.next;
2792 }
2793
2794 struct yaffs_dev *yaffs_next_dev(void)
2795 {
2796         struct yaffs_dev *retval;
2797
2798         if(!dev_iterator)
2799                 return NULL;
2800         if(dev_iterator == &yaffsfs_deviceList)
2801                 return NULL;
2802
2803         retval = list_entry(dev_iterator, struct yaffs_dev, dev_list);
2804         dev_iterator = dev_iterator->next;
2805         return retval;
2806 }
2807
2808 /* Directory search stuff. */
2809
2810
2811 static struct list_head search_contexts;
2812
2813
2814 static void yaffsfs_SetDirRewound(yaffsfs_DirectorySearchContext *dsc)
2815 {
2816         if(dsc &&
2817            dsc->dirObj &&
2818            dsc->dirObj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY){
2819
2820            dsc->offset = 0;
2821
2822            if( list_empty(&dsc->dirObj->variant.dir_variant.children))
2823                 dsc->nextReturn = NULL;
2824            else
2825                 dsc->nextReturn = list_entry(dsc->dirObj->variant.dir_variant.children.next,
2826                                                 struct yaffs_obj,siblings);
2827         } else {
2828                 /* Hey someone isn't playing nice! */
2829         }
2830 }
2831
2832 static void yaffsfs_DirAdvance(yaffsfs_DirectorySearchContext *dsc)
2833 {
2834         if(dsc &&
2835            dsc->dirObj &&
2836            dsc->dirObj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY){
2837
2838            if( dsc->nextReturn == NULL ||
2839                list_empty(&dsc->dirObj->variant.dir_variant.children))
2840                 dsc->nextReturn = NULL;
2841            else {
2842                    struct list_head *next = dsc->nextReturn->siblings.next;
2843
2844                    if( next == &dsc->dirObj->variant.dir_variant.children)
2845                         dsc->nextReturn = NULL; /* end of list */
2846                    else
2847                         dsc->nextReturn = list_entry(next,struct yaffs_obj,siblings);
2848            }
2849         } else {
2850                 /* Hey someone isn't playing nice! */
2851         }
2852 }
2853
2854 static void yaffsfs_RemoveObjectCallback(struct yaffs_obj *obj)
2855 {
2856
2857         struct list_head *i;
2858         yaffsfs_DirectorySearchContext *dsc;
2859
2860         /* if search contexts not initilised then skip */
2861         if(!search_contexts.next)
2862                 return;
2863
2864         /* Iterate through the directory search contexts.
2865          * If any are the one being removed, then advance the dsc to
2866          * the next one to prevent a hanging ptr.
2867          */
2868          list_for_each(i, &search_contexts) {
2869                 if (i) {
2870                         dsc = list_entry(i, yaffsfs_DirectorySearchContext,others);
2871                         if(dsc->nextReturn == obj)
2872                                 yaffsfs_DirAdvance(dsc);
2873                 }
2874         }
2875
2876 }
2877
2878 yaffs_DIR *yaffs_opendir(const YCHAR *dirname)
2879 {
2880         yaffs_DIR *dir = NULL;
2881         struct yaffs_obj *obj = NULL;
2882         yaffsfs_DirectorySearchContext *dsc = NULL;
2883         int notDir = 0;
2884         int loop = 0;
2885
2886         if(!dirname){
2887                 yaffsfs_SetError(-EFAULT);
2888                 return NULL;
2889         }
2890
2891         if(yaffsfs_CheckPath(dirname) < 0){
2892                 yaffsfs_SetError(-ENAMETOOLONG);
2893                 return NULL;
2894         }
2895
2896         yaffsfs_Lock();
2897
2898         obj = yaffsfs_FindObject(NULL,dirname,0,1,NULL,&notDir,&loop);
2899
2900         if(!obj && notDir)
2901                 yaffsfs_SetError(-ENOTDIR);
2902         else if(loop)
2903                 yaffsfs_SetError(-ELOOP);
2904         else if(!obj)
2905                 yaffsfs_SetError(-ENOENT);
2906         else if(obj->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
2907                 yaffsfs_SetError(-ENOTDIR);
2908         else {
2909                 int i;
2910
2911                 for(i = 0, dsc = NULL; i < YAFFSFS_N_DSC && !dsc; i++) {
2912                         if(!yaffsfs_dsc[i].inUse)
2913                                 dsc = & yaffsfs_dsc[i];
2914                 }
2915
2916                 dir = (yaffs_DIR *)dsc;
2917
2918                 if(dsc){
2919                         memset(dsc,0,sizeof(yaffsfs_DirectorySearchContext));
2920                         dsc->inUse = 1;
2921                         dsc->dirObj = obj;
2922                         yaffs_strncpy(dsc->name,dirname,NAME_MAX);
2923                         INIT_LIST_HEAD(&dsc->others);
2924
2925                         if(!search_contexts.next)
2926                                 INIT_LIST_HEAD(&search_contexts);
2927
2928                         list_add(&dsc->others,&search_contexts);
2929                         yaffsfs_SetDirRewound(dsc);
2930                 }
2931
2932         }
2933
2934         yaffsfs_Unlock();
2935
2936         return dir;
2937 }
2938
2939 struct yaffs_dirent *yaffs_readdir(yaffs_DIR *dirp)
2940 {
2941         yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
2942         struct yaffs_dirent *retVal = NULL;
2943
2944         yaffsfs_Lock();
2945
2946         if(dsc && dsc->inUse){
2947                 yaffsfs_SetError(0);
2948                 if(dsc->nextReturn){
2949                         dsc->de.d_ino = yaffs_get_equivalent_obj(dsc->nextReturn)->obj_id;
2950                         dsc->de.d_dont_use = (unsigned)dsc->nextReturn;
2951                         dsc->de.d_off = dsc->offset++;
2952                         yaffs_get_obj_name(dsc->nextReturn,dsc->de.d_name,NAME_MAX);
2953                         if(yaffs_strnlen(dsc->de.d_name,NAME_MAX+1) == 0)
2954                         {
2955                                 /* this should not happen! */
2956                                 yaffs_strcpy(dsc->de.d_name,_Y("zz"));
2957                         }
2958                         dsc->de.d_reclen = sizeof(struct yaffs_dirent);
2959                         retVal = &dsc->de;
2960                         yaffsfs_DirAdvance(dsc);
2961                 } else
2962                         retVal = NULL;
2963         } else
2964                 yaffsfs_SetError(-EBADF);
2965
2966         yaffsfs_Unlock();
2967
2968         return retVal;
2969
2970 }
2971
2972
2973 void yaffs_rewinddir(yaffs_DIR *dirp)
2974 {
2975         yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
2976
2977         yaffsfs_Lock();
2978
2979         yaffsfs_SetDirRewound(dsc);
2980
2981         yaffsfs_Unlock();
2982 }
2983
2984
2985 int yaffs_closedir(yaffs_DIR *dirp)
2986 {
2987         yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
2988
2989         if(!dsc){
2990                 yaffsfs_SetError(-EFAULT);
2991                 return -1;
2992         }
2993
2994         yaffsfs_Lock();
2995         dsc->inUse = 0;
2996         list_del(&dsc->others); /* unhook from list */
2997         yaffsfs_Unlock();
2998         return 0;
2999 }
3000
3001 /* End of directory stuff */
3002
3003
3004 int yaffs_symlink(const YCHAR *oldpath, const YCHAR *newpath)
3005 {
3006         struct yaffs_obj *parent = NULL;
3007         struct yaffs_obj *obj;
3008         YCHAR *name;
3009         int retVal= -1;
3010         int mode = 0; /* ignore for now */
3011         int notDir = 0;
3012         int loop = 0;
3013
3014         if(!oldpath || !newpath){
3015                 yaffsfs_SetError(-EFAULT);
3016                 return -1;
3017         }
3018
3019         if(yaffsfs_CheckPath(newpath) < 0 ||
3020                 yaffsfs_CheckPath(oldpath) < 0){
3021                 yaffsfs_SetError(-ENAMETOOLONG);
3022                 return -1;
3023         }
3024
3025         yaffsfs_Lock();
3026         parent = yaffsfs_FindDirectory(NULL,newpath,&name,0,&notDir,&loop);
3027         if(!parent && notDir)
3028                 yaffsfs_SetError(-ENOTDIR);
3029         else if(loop)
3030                 yaffsfs_SetError(-ELOOP);
3031         else if( !parent || yaffs_strnlen(name,5) < 1)
3032                 yaffsfs_SetError(-ENOENT);
3033         else if(yaffsfs_TooManyObjects(parent->my_dev))
3034                 yaffsfs_SetError(-ENFILE);
3035         else if(parent->my_dev->read_only)
3036                 yaffsfs_SetError(-EROFS);
3037         else if(parent){
3038                 obj = yaffs_create_symlink(parent,name,mode,0,0,oldpath);
3039                 if(obj)
3040                         retVal = 0;
3041                 else if (yaffsfs_FindObject(NULL,newpath,0,0, NULL,NULL,NULL))
3042                         yaffsfs_SetError(-EEXIST);
3043                 else
3044                         yaffsfs_SetError(-ENOSPC);
3045         }
3046
3047         yaffsfs_Unlock();
3048
3049         return retVal;
3050
3051 }
3052
3053 int yaffs_readlink(const YCHAR *path, YCHAR *buf, int bufsiz)
3054 {
3055         struct yaffs_obj *obj = NULL;
3056         struct yaffs_obj *dir = NULL;
3057         int retVal= -1;
3058         int notDir = 0;
3059         int loop = 0;
3060
3061         if(!path || !buf){
3062                 yaffsfs_SetError(-EFAULT);
3063                 return -1;
3064         }
3065
3066         yaffsfs_Lock();
3067
3068         obj = yaffsfs_FindObject(NULL,path,0,1, &dir,&notDir,&loop);
3069
3070         if(!dir && notDir)
3071                 yaffsfs_SetError(-ENOTDIR);
3072         else if(loop)
3073                 yaffsfs_SetError(-ELOOP);
3074         else if(!dir || !obj)
3075                 yaffsfs_SetError(-ENOENT);
3076         else if(obj->variant_type != YAFFS_OBJECT_TYPE_SYMLINK)
3077                 yaffsfs_SetError(-EINVAL);
3078         else {
3079                 YCHAR *alias = obj->variant.symlink_variant.alias;
3080                 memset(buf,0,bufsiz);
3081                 yaffs_strncpy(buf,alias,bufsiz - 1);
3082                 retVal = 0;
3083         }
3084         yaffsfs_Unlock();
3085         return retVal;
3086 }
3087
3088 int yaffs_link(const YCHAR *oldpath, const YCHAR *linkpath)
3089 {
3090         /* Creates a link called newpath to existing oldpath */
3091         struct yaffs_obj *obj = NULL;
3092         struct yaffs_obj *lnk = NULL;
3093         struct yaffs_obj *obj_dir = NULL;
3094         struct yaffs_obj *lnk_dir = NULL;
3095         int retVal = -1;
3096         int notDirObj = 0;
3097         int notDirLnk = 0;
3098         int objLoop = 0;
3099         int lnkLoop = 0;
3100         YCHAR *newname;
3101
3102         if(!oldpath || !linkpath){
3103                 yaffsfs_SetError(-EFAULT);
3104                 return -1;
3105         }
3106
3107         if(yaffsfs_CheckPath(linkpath) < 0 ||
3108                 yaffsfs_CheckPath(oldpath) < 0){
3109                 yaffsfs_SetError(-ENAMETOOLONG);
3110                 return -1;
3111         }
3112
3113         yaffsfs_Lock();
3114
3115         obj = yaffsfs_FindObject(NULL,oldpath,0,1,&obj_dir,&notDirObj,&objLoop);
3116         lnk = yaffsfs_FindObject(NULL,linkpath,0,0,NULL,NULL,NULL);
3117         lnk_dir = yaffsfs_FindDirectory(NULL,linkpath,&newname,0,&notDirLnk,&lnkLoop);
3118
3119         if((!obj_dir && notDirObj) || (!lnk_dir && notDirLnk))
3120                 yaffsfs_SetError(-ENOTDIR);
3121         else if(objLoop || lnkLoop)
3122                 yaffsfs_SetError(-ELOOP);
3123         else if(!obj_dir || !lnk_dir || !obj)
3124                 yaffsfs_SetError(-ENOENT);
3125         else if(obj->my_dev->read_only)
3126                 yaffsfs_SetError(-EROFS);
3127         else if(yaffsfs_TooManyObjects(obj->my_dev))
3128                 yaffsfs_SetError(-ENFILE);
3129         else if(lnk)
3130                 yaffsfs_SetError(-EEXIST);
3131         else if(lnk_dir->my_dev != obj->my_dev)
3132                 yaffsfs_SetError(-EXDEV);
3133         else {
3134                 retVal = yaffsfs_CheckNameLength(newname);
3135
3136                 if(retVal == 0) {
3137                         lnk = yaffs_link_obj(lnk_dir,newname,obj);
3138                         if(lnk)
3139                                 retVal = 0;
3140                         else{
3141                                 yaffsfs_SetError(-ENOSPC);
3142                                 retVal = -1;
3143                         }
3144                 }
3145         }
3146         yaffsfs_Unlock();
3147
3148         return retVal;
3149 }
3150
3151 int yaffs_mknod(const YCHAR *pathname, mode_t mode, dev_t dev)
3152 {
3153         pathname=pathname;
3154         mode=mode;
3155         dev=dev;
3156
3157         yaffsfs_SetError(-EINVAL);
3158         return -1;
3159 }
3160
3161
3162 /*
3163  * D E B U G   F U N C T I O N S
3164  */
3165
3166 /*
3167  * yaffs_n_handles()
3168  * Returns number of handles attached to the object
3169  */
3170 int yaffs_n_handles(const YCHAR *path)
3171 {
3172         struct yaffs_obj *obj;
3173
3174         if(!path){
3175                 yaffsfs_SetError(-EFAULT);
3176                 return -1;
3177         }
3178
3179         if(yaffsfs_CheckPath(path) < 0){
3180                 yaffsfs_SetError(-ENAMETOOLONG);
3181                 return -1;
3182         }
3183
3184         obj = yaffsfs_FindObject(NULL,path,0,1,NULL,NULL,NULL);
3185
3186         if(obj)
3187                 return yaffsfs_CountHandles(obj);
3188         else
3189                 return -1;
3190 }
3191
3192 int yaffs_get_error(void)
3193 {
3194         return yaffsfs_GetLastError();
3195 }
3196
3197 int yaffs_set_error(int error)
3198 {
3199         yaffsfs_SetError(error);
3200         return 0;
3201 }
3202
3203 int yaffs_dump_dev(const YCHAR *path)
3204 {
3205 #if 1
3206         path=path;
3207 #else
3208         YCHAR *rest;
3209
3210         struct yaffs_obj *obj = yaffsfs_FindRoot(path,&rest);
3211
3212         if(obj){
3213                 struct yaffs_dev *dev = obj->my_dev;
3214
3215                 printf("\n"
3216                            "n_page_writes.......... %d\n"
3217                            "n_page_reads........... %d\n"
3218                            "n_erasures....... %d\n"
3219                            "n_gc_copies............ %d\n"
3220                            "garbageCollections... %d\n"
3221                            "passiveGarbageColl'ns %d\n"
3222                            "\n",
3223                                 dev->n_page_writes,
3224                                 dev->n_page_reads,
3225                                 dev->n_erasures,
3226                                 dev->n_gc_copies,
3227                                 dev->garbageCollections,
3228                                 dev->passiveGarbageCollections
3229                 );
3230
3231         }
3232
3233 #endif
3234         return 0;
3235 }
3236