xref: /openbmc/u-boot/fs/yaffs2/yaffsfs.c (revision f214a20e)
1 /*
2  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3  *
4  * Copyright (C) 2002-2007 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 /* XXX U-BOOT XXX */
15 #include <common.h>
16 #include <malloc.h>
17 
18 #include "yaffsfs.h"
19 #include "yaffs_guts.h"
20 #include "yaffscfg.h"
21 #include "yportenv.h"
22 
23 /* XXX U-BOOT XXX */
24 #if 0
25 #include <string.h> // for memset
26 #endif
27 
28 #define YAFFSFS_MAX_SYMLINK_DEREFERENCES 5
29 
30 #ifndef NULL
31 #define NULL ((void *)0)
32 #endif
33 
34 
35 const char *yaffsfs_c_version="$Id: yaffsfs.c,v 1.18 2007/07/18 19:40:38 charles Exp $";
36 
37 // configurationList is the list of devices that are supported
38 static yaffsfs_DeviceConfiguration *yaffsfs_configurationList;
39 
40 
41 /* Some forward references */
42 static yaffs_Object *yaffsfs_FindObject(yaffs_Object *relativeDirectory, const char *path, int symDepth);
43 static void yaffsfs_RemoveObjectCallback(yaffs_Object *obj);
44 
45 
46 // Handle management.
47 //
48 
49 
50 unsigned int yaffs_wr_attempts;
51 
52 typedef struct
53 {
54 	__u8  inUse:1;		// this handle is in use
55 	__u8  readOnly:1;	// this handle is read only
56 	__u8  append:1;		// append only
57 	__u8  exclusive:1;	// exclusive
58 	__u32 position;		// current position in file
59 	yaffs_Object *obj;	// the object
60 }yaffsfs_Handle;
61 
62 
63 static yaffsfs_Handle yaffsfs_handle[YAFFSFS_N_HANDLES];
64 
65 // yaffsfs_InitHandle
66 /// Inilitalise handles on start-up.
67 //
68 static int yaffsfs_InitHandles(void)
69 {
70 	int i;
71 	for(i = 0; i < YAFFSFS_N_HANDLES; i++)
72 	{
73 		yaffsfs_handle[i].inUse = 0;
74 		yaffsfs_handle[i].obj = NULL;
75 	}
76 	return 0;
77 }
78 
79 yaffsfs_Handle *yaffsfs_GetHandlePointer(int h)
80 {
81 	if(h < 0 || h >= YAFFSFS_N_HANDLES)
82 	{
83 		return NULL;
84 	}
85 
86 	return &yaffsfs_handle[h];
87 }
88 
89 yaffs_Object *yaffsfs_GetHandleObject(int handle)
90 {
91 	yaffsfs_Handle *h = yaffsfs_GetHandlePointer(handle);
92 
93 	if(h && h->inUse)
94 	{
95 		return h->obj;
96 	}
97 
98 	return NULL;
99 }
100 
101 
102 //yaffsfs_GetHandle
103 // Grab a handle (when opening a file)
104 //
105 
106 static int yaffsfs_GetHandle(void)
107 {
108 	int i;
109 	yaffsfs_Handle *h;
110 
111 	for(i = 0; i < YAFFSFS_N_HANDLES; i++)
112 	{
113 		h = yaffsfs_GetHandlePointer(i);
114 		if(!h)
115 		{
116 			// todo bug: should never happen
117 		}
118 		if(!h->inUse)
119 		{
120 			memset(h,0,sizeof(yaffsfs_Handle));
121 			h->inUse=1;
122 			return i;
123 		}
124 	}
125 	return -1;
126 }
127 
128 // yaffs_PutHandle
129 // Let go of a handle (when closing a file)
130 //
131 static int yaffsfs_PutHandle(int handle)
132 {
133 	yaffsfs_Handle *h = yaffsfs_GetHandlePointer(handle);
134 
135 	if(h)
136 	{
137 		h->inUse = 0;
138 		h->obj = NULL;
139 	}
140 	return 0;
141 }
142 
143 
144 
145 // Stuff to search for a directory from a path
146 
147 
148 int yaffsfs_Match(char a, char b)
149 {
150 	// case sensitive
151 	return (a == b);
152 }
153 
154 // yaffsfs_FindDevice
155 // yaffsfs_FindRoot
156 // Scan the configuration list to find the root.
157 // Curveballs: Should match paths that end in '/' too
158 // Curveball2 Might have "/x/ and "/x/y". Need to return the longest match
159 static yaffs_Device *yaffsfs_FindDevice(const char *path, char **restOfPath)
160 {
161 	yaffsfs_DeviceConfiguration *cfg = yaffsfs_configurationList;
162 	const char *leftOver;
163 	const char *p;
164 	yaffs_Device *retval = NULL;
165 	int thisMatchLength;
166 	int longestMatch = -1;
167 
168 	// Check all configs, choose the one that:
169 	// 1) Actually matches a prefix (ie /a amd /abc will not match
170 	// 2) Matches the longest.
171 	while(cfg && cfg->prefix && cfg->dev)
172 	{
173 		leftOver = path;
174 		p = cfg->prefix;
175 		thisMatchLength = 0;
176 
177 		while(*p &&  //unmatched part of prefix
178 		      strcmp(p,"/") && // the rest of the prefix is not / (to catch / at end)
179 		      *leftOver &&
180 		      yaffsfs_Match(*p,*leftOver))
181 		{
182 			p++;
183 			leftOver++;
184 			thisMatchLength++;
185 		}
186 		if((!*p || strcmp(p,"/") == 0) &&      // end of prefix
187 		   (!*leftOver || *leftOver == '/') && // no more in this path name part
188 		   (thisMatchLength > longestMatch))
189 		{
190 			// Matched prefix
191 			*restOfPath = (char *)leftOver;
192 			retval = cfg->dev;
193 			longestMatch = thisMatchLength;
194 		}
195 		cfg++;
196 	}
197 	return retval;
198 }
199 
200 static yaffs_Object *yaffsfs_FindRoot(const char *path, char **restOfPath)
201 {
202 
203 	yaffs_Device *dev;
204 
205 	dev= yaffsfs_FindDevice(path,restOfPath);
206 	if(dev && dev->isMounted)
207 	{
208 		return dev->rootDir;
209 	}
210 	return NULL;
211 }
212 
213 static yaffs_Object *yaffsfs_FollowLink(yaffs_Object *obj,int symDepth)
214 {
215 
216 	while(obj && obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
217 	{
218 		char *alias = obj->variant.symLinkVariant.alias;
219 
220 		if(*alias == '/')
221 		{
222 			// Starts with a /, need to scan from root up
223 			obj = yaffsfs_FindObject(NULL,alias,symDepth++);
224 		}
225 		else
226 		{
227 			// Relative to here, so use the parent of the symlink as a start
228 			obj = yaffsfs_FindObject(obj->parent,alias,symDepth++);
229 		}
230 	}
231 	return obj;
232 }
233 
234 
235 // yaffsfs_FindDirectory
236 // Parse a path to determine the directory and the name within the directory.
237 //
238 // eg. "/data/xx/ff" --> puts name="ff" and returns the directory "/data/xx"
239 static yaffs_Object *yaffsfs_DoFindDirectory(yaffs_Object *startDir,const char *path,char **name,int symDepth)
240 {
241 	yaffs_Object *dir;
242 	char *restOfPath;
243 	char str[YAFFS_MAX_NAME_LENGTH+1];
244 	int i;
245 
246 	if(symDepth > YAFFSFS_MAX_SYMLINK_DEREFERENCES)
247 	{
248 		return NULL;
249 	}
250 
251 	if(startDir)
252 	{
253 		dir = startDir;
254 		restOfPath = (char *)path;
255 	}
256 	else
257 	{
258 		dir = yaffsfs_FindRoot(path,&restOfPath);
259 	}
260 
261 	while(dir)
262 	{
263 		// parse off /.
264 		// curve ball: also throw away surplus '/'
265 		// eg. "/ram/x////ff" gets treated the same as "/ram/x/ff"
266 		while(*restOfPath == '/')
267 		{
268 			restOfPath++; // get rid of '/'
269 		}
270 
271 		*name = restOfPath;
272 		i = 0;
273 
274 		while(*restOfPath && *restOfPath != '/')
275 		{
276 			if (i < YAFFS_MAX_NAME_LENGTH)
277 			{
278 				str[i] = *restOfPath;
279 				str[i+1] = '\0';
280 				i++;
281 			}
282 			restOfPath++;
283 		}
284 
285 		if(!*restOfPath)
286 		{
287 			// got to the end of the string
288 			return dir;
289 		}
290 		else
291 		{
292 			if(strcmp(str,".") == 0)
293 			{
294 				// Do nothing
295 			}
296 			else if(strcmp(str,"..") == 0)
297 			{
298 				dir = dir->parent;
299 			}
300 			else
301 			{
302 				dir = yaffs_FindObjectByName(dir,str);
303 
304 				while(dir && dir->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
305 				{
306 
307 					dir = yaffsfs_FollowLink(dir,symDepth);
308 
309 				}
310 
311 				if(dir && dir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
312 				{
313 					dir = NULL;
314 				}
315 			}
316 		}
317 	}
318 	// directory did not exist.
319 	return NULL;
320 }
321 
322 static yaffs_Object *yaffsfs_FindDirectory(yaffs_Object *relativeDirectory,const char *path,char **name,int symDepth)
323 {
324 	return yaffsfs_DoFindDirectory(relativeDirectory,path,name,symDepth);
325 }
326 
327 // yaffsfs_FindObject turns a path for an existing object into the object
328 //
329 static yaffs_Object *yaffsfs_FindObject(yaffs_Object *relativeDirectory, const char *path,int symDepth)
330 {
331 	yaffs_Object *dir;
332 	char *name;
333 
334 	dir = yaffsfs_FindDirectory(relativeDirectory,path,&name,symDepth);
335 
336 	if(dir && *name)
337 	{
338 		return yaffs_FindObjectByName(dir,name);
339 	}
340 
341 	return dir;
342 }
343 
344 
345 
346 int yaffs_open(const char *path, int oflag, int mode)
347 {
348 	yaffs_Object *obj = NULL;
349 	yaffs_Object *dir = NULL;
350 	char *name;
351 	int handle = -1;
352 	yaffsfs_Handle *h = NULL;
353 	int alreadyOpen = 0;
354 	int alreadyExclusive = 0;
355 	int openDenied = 0;
356 	int symDepth = 0;
357 	int errorReported = 0;
358 
359 	int i;
360 
361 
362 	// todo sanity check oflag (eg. can't have O_TRUNC without WRONLY or RDWR
363 
364 
365 	yaffsfs_Lock();
366 
367 	handle = yaffsfs_GetHandle();
368 
369 	if(handle >= 0)
370 	{
371 
372 		h = yaffsfs_GetHandlePointer(handle);
373 
374 
375 		// try to find the exisiting object
376 		obj = yaffsfs_FindObject(NULL,path,0);
377 
378 		if(obj && obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
379 		{
380 
381 			obj = yaffsfs_FollowLink(obj,symDepth++);
382 		}
383 
384 		if(obj)
385 		{
386 			// Check if the object is already in use
387 			alreadyOpen = alreadyExclusive = 0;
388 
389 			for(i = 0; i <= YAFFSFS_N_HANDLES; i++)
390 			{
391 
392 				if(i != handle &&
393 				   yaffsfs_handle[i].inUse &&
394 				    obj == yaffsfs_handle[i].obj)
395 				 {
396 				 	alreadyOpen = 1;
397 					if(yaffsfs_handle[i].exclusive)
398 					{
399 						alreadyExclusive = 1;
400 					}
401 				 }
402 			}
403 
404 			if(((oflag & O_EXCL) && alreadyOpen) || alreadyExclusive)
405 			{
406 				openDenied = 1;
407 			}
408 
409 			// Open should fail if O_CREAT and O_EXCL are specified
410 			if((oflag & O_EXCL) && (oflag & O_CREAT))
411 			{
412 				openDenied = 1;
413 				yaffsfs_SetError(-EEXIST);
414 				errorReported = 1;
415 			}
416 
417 			// Check file permissions
418 			if( (oflag & (O_RDWR | O_WRONLY)) == 0 &&     // ie O_RDONLY
419 			   !(obj->yst_mode & S_IREAD))
420 			{
421 				openDenied = 1;
422 			}
423 
424 			if( (oflag & O_RDWR) &&
425 			   !(obj->yst_mode & S_IREAD))
426 			{
427 				openDenied = 1;
428 			}
429 
430 			if( (oflag & (O_RDWR | O_WRONLY)) &&
431 			   !(obj->yst_mode & S_IWRITE))
432 			{
433 				openDenied = 1;
434 			}
435 
436 		}
437 
438 		else if((oflag & O_CREAT))
439 		{
440 			// Let's see if we can create this file
441 			dir = yaffsfs_FindDirectory(NULL,path,&name,0);
442 			if(dir)
443 			{
444 				obj = yaffs_MknodFile(dir,name,mode,0,0);
445 			}
446 			else
447 			{
448 				yaffsfs_SetError(-ENOTDIR);
449 			}
450 		}
451 
452 		if(obj && !openDenied)
453 		{
454 			h->obj = obj;
455 			h->inUse = 1;
456 	    	h->readOnly = (oflag & (O_WRONLY | O_RDWR)) ? 0 : 1;
457 			h->append =  (oflag & O_APPEND) ? 1 : 0;
458 			h->exclusive = (oflag & O_EXCL) ? 1 : 0;
459 			h->position = 0;
460 
461 			obj->inUse++;
462 			if((oflag & O_TRUNC) && !h->readOnly)
463 			{
464 				//todo truncate
465 				yaffs_ResizeFile(obj,0);
466 			}
467 
468 		}
469 		else
470 		{
471 			yaffsfs_PutHandle(handle);
472 			if(!errorReported)
473 			{
474 				yaffsfs_SetError(-EACCESS);
475 				errorReported = 1;
476 			}
477 			handle = -1;
478 		}
479 
480 	}
481 
482 	yaffsfs_Unlock();
483 
484 	return handle;
485 }
486 
487 int yaffs_close(int fd)
488 {
489 	yaffsfs_Handle *h = NULL;
490 	int retVal = 0;
491 
492 	yaffsfs_Lock();
493 
494 	h = yaffsfs_GetHandlePointer(fd);
495 
496 	if(h && h->inUse)
497 	{
498 		// clean up
499 		yaffs_FlushFile(h->obj,1);
500 		h->obj->inUse--;
501 		if(h->obj->inUse <= 0 && h->obj->unlinked)
502 		{
503 			yaffs_DeleteFile(h->obj);
504 		}
505 		yaffsfs_PutHandle(fd);
506 		retVal = 0;
507 	}
508 	else
509 	{
510 		// bad handle
511 		yaffsfs_SetError(-EBADF);
512 		retVal = -1;
513 	}
514 
515 	yaffsfs_Unlock();
516 
517 	return retVal;
518 }
519 
520 int yaffs_read(int fd, void *buf, unsigned int nbyte)
521 {
522 	yaffsfs_Handle *h = NULL;
523 	yaffs_Object *obj = NULL;
524 	int pos = 0;
525 	int nRead = -1;
526 	int maxRead;
527 
528 	yaffsfs_Lock();
529 	h = yaffsfs_GetHandlePointer(fd);
530 	obj = yaffsfs_GetHandleObject(fd);
531 
532 	if(!h || !obj)
533 	{
534 		// bad handle
535 		yaffsfs_SetError(-EBADF);
536 	}
537 	else if( h && obj)
538 	{
539 		pos=  h->position;
540 		if(yaffs_GetObjectFileLength(obj) > pos)
541 		{
542 			maxRead = yaffs_GetObjectFileLength(obj) - pos;
543 		}
544 		else
545 		{
546 			maxRead = 0;
547 		}
548 
549 		if(nbyte > maxRead)
550 		{
551 			nbyte = maxRead;
552 		}
553 
554 
555 		if(nbyte > 0)
556 		{
557 			nRead = yaffs_ReadDataFromFile(obj,buf,pos,nbyte);
558 			if(nRead >= 0)
559 			{
560 				h->position = pos + nRead;
561 			}
562 			else
563 			{
564 				//todo error
565 			}
566 		}
567 		else
568 		{
569 			nRead = 0;
570 		}
571 
572 	}
573 
574 	yaffsfs_Unlock();
575 
576 
577 	return (nRead >= 0) ? nRead : -1;
578 
579 }
580 
581 int yaffs_write(int fd, const void *buf, unsigned int nbyte)
582 {
583 	yaffsfs_Handle *h = NULL;
584 	yaffs_Object *obj = NULL;
585 	int pos = 0;
586 	int nWritten = -1;
587 	int writeThrough = 0;
588 
589 	yaffsfs_Lock();
590 	h = yaffsfs_GetHandlePointer(fd);
591 	obj = yaffsfs_GetHandleObject(fd);
592 
593 	if(!h || !obj)
594 	{
595 		// bad handle
596 		yaffsfs_SetError(-EBADF);
597 	}
598 	else if( h && obj && h->readOnly)
599 	{
600 		// todo error
601 	}
602 	else if( h && obj)
603 	{
604 		if(h->append)
605 		{
606 			pos =  yaffs_GetObjectFileLength(obj);
607 		}
608 		else
609 		{
610 			pos = h->position;
611 		}
612 
613 		nWritten = yaffs_WriteDataToFile(obj,buf,pos,nbyte,writeThrough);
614 
615 		if(nWritten >= 0)
616 		{
617 			h->position = pos + nWritten;
618 		}
619 		else
620 		{
621 			//todo error
622 		}
623 
624 	}
625 
626 	yaffsfs_Unlock();
627 
628 
629 	return (nWritten >= 0) ? nWritten : -1;
630 
631 }
632 
633 int yaffs_truncate(int fd, off_t newSize)
634 {
635 	yaffsfs_Handle *h = NULL;
636 	yaffs_Object *obj = NULL;
637 	int result = 0;
638 
639 	yaffsfs_Lock();
640 	h = yaffsfs_GetHandlePointer(fd);
641 	obj = yaffsfs_GetHandleObject(fd);
642 
643 	if(!h || !obj)
644 	{
645 		// bad handle
646 		yaffsfs_SetError(-EBADF);
647 	}
648 	else
649 	{
650 		// resize the file
651 		result = yaffs_ResizeFile(obj,newSize);
652 	}
653 	yaffsfs_Unlock();
654 
655 
656 	return (result) ? 0 : -1;
657 
658 }
659 
660 off_t yaffs_lseek(int fd, off_t offset, int whence)
661 {
662 	yaffsfs_Handle *h = NULL;
663 	yaffs_Object *obj = NULL;
664 	int pos = -1;
665 	int fSize = -1;
666 
667 	yaffsfs_Lock();
668 	h = yaffsfs_GetHandlePointer(fd);
669 	obj = yaffsfs_GetHandleObject(fd);
670 
671 	if(!h || !obj)
672 	{
673 		// bad handle
674 		yaffsfs_SetError(-EBADF);
675 	}
676 	else if(whence == SEEK_SET)
677 	{
678 		if(offset >= 0)
679 		{
680 			pos = offset;
681 		}
682 	}
683 	else if(whence == SEEK_CUR)
684 	{
685 		if( (h->position + offset) >= 0)
686 		{
687 			pos = (h->position + offset);
688 		}
689 	}
690 	else if(whence == SEEK_END)
691 	{
692 		fSize = yaffs_GetObjectFileLength(obj);
693 		if(fSize >= 0 && (fSize + offset) >= 0)
694 		{
695 			pos = fSize + offset;
696 		}
697 	}
698 
699 	if(pos >= 0)
700 	{
701 		h->position = pos;
702 	}
703 	else
704 	{
705 		// todo error
706 	}
707 
708 
709 	yaffsfs_Unlock();
710 
711 	return pos;
712 }
713 
714 
715 int yaffsfs_DoUnlink(const char *path,int isDirectory)
716 {
717 	yaffs_Object *dir = NULL;
718 	yaffs_Object *obj = NULL;
719 	char *name;
720 	int result = YAFFS_FAIL;
721 
722 	yaffsfs_Lock();
723 
724 	obj = yaffsfs_FindObject(NULL,path,0);
725 	dir = yaffsfs_FindDirectory(NULL,path,&name,0);
726 	if(!dir)
727 	{
728 		yaffsfs_SetError(-ENOTDIR);
729 	}
730 	else if(!obj)
731 	{
732 		yaffsfs_SetError(-ENOENT);
733 	}
734 	else if(!isDirectory && obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
735 	{
736 		yaffsfs_SetError(-EISDIR);
737 	}
738 	else if(isDirectory && obj->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
739 	{
740 		yaffsfs_SetError(-ENOTDIR);
741 	}
742 	else
743 	{
744 		result = yaffs_Unlink(dir,name);
745 
746 		if(result == YAFFS_FAIL && isDirectory)
747 		{
748 			yaffsfs_SetError(-ENOTEMPTY);
749 		}
750 	}
751 
752 	yaffsfs_Unlock();
753 
754 	// todo error
755 
756 	return (result == YAFFS_FAIL) ? -1 : 0;
757 }
758 int yaffs_rmdir(const char *path)
759 {
760 	return yaffsfs_DoUnlink(path,1);
761 }
762 
763 int yaffs_unlink(const char *path)
764 {
765 	return yaffsfs_DoUnlink(path,0);
766 }
767 
768 int yaffs_rename(const char *oldPath, const char *newPath)
769 {
770 	yaffs_Object *olddir = NULL;
771 	yaffs_Object *newdir = NULL;
772 	yaffs_Object *obj = NULL;
773 	char *oldname;
774 	char *newname;
775 	int result= YAFFS_FAIL;
776 	int renameAllowed = 1;
777 
778 	yaffsfs_Lock();
779 
780 	olddir = yaffsfs_FindDirectory(NULL,oldPath,&oldname,0);
781 	newdir = yaffsfs_FindDirectory(NULL,newPath,&newname,0);
782 	obj = yaffsfs_FindObject(NULL,oldPath,0);
783 
784 	if(!olddir || !newdir || !obj)
785 	{
786 		// bad file
787 		yaffsfs_SetError(-EBADF);
788 		renameAllowed = 0;
789 	}
790 	else if(olddir->myDev != newdir->myDev)
791 	{
792 		// oops must be on same device
793 		// todo error
794 		yaffsfs_SetError(-EXDEV);
795 		renameAllowed = 0;
796 	}
797 	else if(obj && obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
798 	{
799 		// It is a directory, check that it is not being renamed to
800 		// being its own decendent.
801 		// Do this by tracing from the new directory back to the root, checking for obj
802 
803 		yaffs_Object *xx = newdir;
804 
805 		while( renameAllowed && xx)
806 		{
807 			if(xx == obj)
808 			{
809 				renameAllowed = 0;
810 			}
811 			xx = xx->parent;
812 		}
813 		if(!renameAllowed) yaffsfs_SetError(-EACCESS);
814 	}
815 
816 	if(renameAllowed)
817 	{
818 		result = yaffs_RenameObject(olddir,oldname,newdir,newname);
819 	}
820 
821 	yaffsfs_Unlock();
822 
823 	return (result == YAFFS_FAIL) ? -1 : 0;
824 }
825 
826 
827 static int yaffsfs_DoStat(yaffs_Object *obj,struct yaffs_stat *buf)
828 {
829 	int retVal = -1;
830 
831 	if(obj)
832 	{
833 		obj = yaffs_GetEquivalentObject(obj);
834 	}
835 
836 	if(obj && buf)
837 	{
838     	buf->st_dev = (int)obj->myDev->genericDevice;
839     	buf->st_ino = obj->objectId;
840     	buf->st_mode = obj->yst_mode & ~S_IFMT; // clear out file type bits
841 
842 		if(obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
843 		{
844 			buf->st_mode |= S_IFDIR;
845 		}
846 		else if(obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
847 		{
848 			buf->st_mode |= S_IFLNK;
849 		}
850 		else if(obj->variantType == YAFFS_OBJECT_TYPE_FILE)
851 		{
852 			buf->st_mode |= S_IFREG;
853 		}
854 
855     	buf->st_nlink = yaffs_GetObjectLinkCount(obj);
856     	buf->st_uid = 0;
857     	buf->st_gid = 0;;
858     	buf->st_rdev = obj->yst_rdev;
859     	buf->st_size = yaffs_GetObjectFileLength(obj);
860 		buf->st_blksize = obj->myDev->nDataBytesPerChunk;
861     	buf->st_blocks = (buf->st_size + buf->st_blksize -1)/buf->st_blksize;
862     	buf->yst_atime = obj->yst_atime;
863     	buf->yst_ctime = obj->yst_ctime;
864     	buf->yst_mtime = obj->yst_mtime;
865 		retVal = 0;
866 	}
867 	return retVal;
868 }
869 
870 static int yaffsfs_DoStatOrLStat(const char *path, struct yaffs_stat *buf,int doLStat)
871 {
872 	yaffs_Object *obj;
873 
874 	int retVal = -1;
875 
876 	yaffsfs_Lock();
877 	obj = yaffsfs_FindObject(NULL,path,0);
878 
879 	if(!doLStat && obj)
880 	{
881 		obj = yaffsfs_FollowLink(obj,0);
882 	}
883 
884 	if(obj)
885 	{
886 		retVal = yaffsfs_DoStat(obj,buf);
887 	}
888 	else
889 	{
890 		// todo error not found
891 		yaffsfs_SetError(-ENOENT);
892 	}
893 
894 	yaffsfs_Unlock();
895 
896 	return retVal;
897 
898 }
899 
900 int yaffs_stat(const char *path, struct yaffs_stat *buf)
901 {
902 	return yaffsfs_DoStatOrLStat(path,buf,0);
903 }
904 
905 int yaffs_lstat(const char *path, struct yaffs_stat *buf)
906 {
907 	return yaffsfs_DoStatOrLStat(path,buf,1);
908 }
909 
910 int yaffs_fstat(int fd, struct yaffs_stat *buf)
911 {
912 	yaffs_Object *obj;
913 
914 	int retVal = -1;
915 
916 	yaffsfs_Lock();
917 	obj = yaffsfs_GetHandleObject(fd);
918 
919 	if(obj)
920 	{
921 		retVal = yaffsfs_DoStat(obj,buf);
922 	}
923 	else
924 	{
925 		// bad handle
926 		yaffsfs_SetError(-EBADF);
927 	}
928 
929 	yaffsfs_Unlock();
930 
931 	return retVal;
932 }
933 
934 static int yaffsfs_DoChMod(yaffs_Object *obj,mode_t mode)
935 {
936 	int result = YAFFS_FAIL;
937 
938 	if(obj)
939 	{
940 		obj = yaffs_GetEquivalentObject(obj);
941 	}
942 
943 	if(obj)
944 	{
945 		obj->yst_mode = mode;
946 		obj->dirty = 1;
947 		result = yaffs_FlushFile(obj,0);
948 	}
949 
950 	return result == YAFFS_OK ? 0 : -1;
951 }
952 
953 
954 int yaffs_chmod(const char *path, mode_t mode)
955 {
956 	yaffs_Object *obj;
957 
958 	int retVal = -1;
959 
960 	yaffsfs_Lock();
961 	obj = yaffsfs_FindObject(NULL,path,0);
962 
963 	if(obj)
964 	{
965 		retVal = yaffsfs_DoChMod(obj,mode);
966 	}
967 	else
968 	{
969 		// todo error not found
970 		yaffsfs_SetError(-ENOENT);
971 	}
972 
973 	yaffsfs_Unlock();
974 
975 	return retVal;
976 
977 }
978 
979 
980 int yaffs_fchmod(int fd, mode_t mode)
981 {
982 	yaffs_Object *obj;
983 
984 	int retVal = -1;
985 
986 	yaffsfs_Lock();
987 	obj = yaffsfs_GetHandleObject(fd);
988 
989 	if(obj)
990 	{
991 		retVal = yaffsfs_DoChMod(obj,mode);
992 	}
993 	else
994 	{
995 		// bad handle
996 		yaffsfs_SetError(-EBADF);
997 	}
998 
999 	yaffsfs_Unlock();
1000 
1001 	return retVal;
1002 }
1003 
1004 
1005 int yaffs_mkdir(const char *path, mode_t mode)
1006 {
1007 	yaffs_Object *parent = NULL;
1008 	yaffs_Object *dir = NULL;
1009 	char *name;
1010 	int retVal= -1;
1011 
1012 	yaffsfs_Lock();
1013 	parent = yaffsfs_FindDirectory(NULL,path,&name,0);
1014 	if(parent)
1015 		dir = yaffs_MknodDirectory(parent,name,mode,0,0);
1016 	if(dir)
1017 	{
1018 		retVal = 0;
1019 	}
1020 	else
1021 	{
1022 		yaffsfs_SetError(-ENOSPC); // just assume no space for now
1023 		retVal = -1;
1024 	}
1025 
1026 	yaffsfs_Unlock();
1027 
1028 	return retVal;
1029 }
1030 
1031 int yaffs_mount(const char *path)
1032 {
1033 	int retVal=-1;
1034 	int result=YAFFS_FAIL;
1035 	yaffs_Device *dev=NULL;
1036 	char *dummy;
1037 
1038 	T(YAFFS_TRACE_ALWAYS,("yaffs: Mounting %s\n",path));
1039 
1040 	yaffsfs_Lock();
1041 	dev = yaffsfs_FindDevice(path,&dummy);
1042 	if(dev)
1043 	{
1044 		if(!dev->isMounted)
1045 		{
1046 			result = yaffs_GutsInitialise(dev);
1047 			if(result == YAFFS_FAIL)
1048 			{
1049 				// todo error - mount failed
1050 				yaffsfs_SetError(-ENOMEM);
1051 			}
1052 			retVal = result ? 0 : -1;
1053 
1054 		}
1055 		else
1056 		{
1057 			//todo error - already mounted.
1058 			yaffsfs_SetError(-EBUSY);
1059 		}
1060 	}
1061 	else
1062 	{
1063 		// todo error - no device
1064 		yaffsfs_SetError(-ENODEV);
1065 	}
1066 	yaffsfs_Unlock();
1067 	return retVal;
1068 
1069 }
1070 
1071 int yaffs_unmount(const char *path)
1072 {
1073 	int retVal=-1;
1074 	yaffs_Device *dev=NULL;
1075 	char *dummy;
1076 
1077 	yaffsfs_Lock();
1078 	dev = yaffsfs_FindDevice(path,&dummy);
1079 	if(dev)
1080 	{
1081 		if(dev->isMounted)
1082 		{
1083 			int i;
1084 			int inUse;
1085 
1086 			yaffs_FlushEntireDeviceCache(dev);
1087 			yaffs_CheckpointSave(dev);
1088 
1089 			for(i = inUse = 0; i < YAFFSFS_N_HANDLES && !inUse; i++)
1090 			{
1091 				if(yaffsfs_handle[i].inUse && yaffsfs_handle[i].obj->myDev == dev)
1092 				{
1093 					inUse = 1; // the device is in use, can't unmount
1094 				}
1095 			}
1096 
1097 			if(!inUse)
1098 			{
1099 				yaffs_Deinitialise(dev);
1100 
1101 				retVal = 0;
1102 			}
1103 			else
1104 			{
1105 				// todo error can't unmount as files are open
1106 				yaffsfs_SetError(-EBUSY);
1107 			}
1108 
1109 		}
1110 		else
1111 		{
1112 			//todo error - not mounted.
1113 			yaffsfs_SetError(-EINVAL);
1114 
1115 		}
1116 	}
1117 	else
1118 	{
1119 		// todo error - no device
1120 		yaffsfs_SetError(-ENODEV);
1121 	}
1122 	yaffsfs_Unlock();
1123 	return retVal;
1124 
1125 }
1126 
1127 loff_t yaffs_freespace(const char *path)
1128 {
1129 	loff_t retVal=-1;
1130 	yaffs_Device *dev=NULL;
1131 	char *dummy;
1132 
1133 	yaffsfs_Lock();
1134 	dev = yaffsfs_FindDevice(path,&dummy);
1135 	if(dev  && dev->isMounted)
1136 	{
1137 		retVal = yaffs_GetNumberOfFreeChunks(dev);
1138 		retVal *= dev->nDataBytesPerChunk;
1139 
1140 	}
1141 	else
1142 	{
1143 		yaffsfs_SetError(-EINVAL);
1144 	}
1145 
1146 	yaffsfs_Unlock();
1147 	return retVal;
1148 }
1149 
1150 
1151 
1152 void yaffs_initialise(yaffsfs_DeviceConfiguration *cfgList)
1153 {
1154 
1155 	yaffsfs_DeviceConfiguration *cfg;
1156 
1157 	yaffsfs_configurationList = cfgList;
1158 
1159 	yaffsfs_InitHandles();
1160 
1161 	cfg = yaffsfs_configurationList;
1162 
1163 	while(cfg && cfg->prefix && cfg->dev)
1164 	{
1165 		cfg->dev->isMounted = 0;
1166 		cfg->dev->removeObjectCallback = yaffsfs_RemoveObjectCallback;
1167 		cfg++;
1168 	}
1169 }
1170 
1171 
1172 //
1173 // Directory search stuff.
1174 
1175 //
1176 // Directory search context
1177 //
1178 // NB this is an opaque structure.
1179 
1180 
1181 typedef struct
1182 {
1183 	__u32 magic;
1184 	yaffs_dirent de;		/* directory entry being used by this dsc */
1185 	char name[NAME_MAX+1];		/* name of directory being searched */
1186 	yaffs_Object *dirObj;		/* ptr to directory being searched */
1187 	yaffs_Object *nextReturn;	/* obj to be returned by next readddir */
1188 	int offset;
1189 	struct list_head others;
1190 } yaffsfs_DirectorySearchContext;
1191 
1192 
1193 
1194 static struct list_head search_contexts;
1195 
1196 
1197 static void yaffsfs_SetDirRewound(yaffsfs_DirectorySearchContext *dsc)
1198 {
1199 	if(dsc &&
1200 	   dsc->dirObj &&
1201 	   dsc->dirObj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY){
1202 
1203 	   dsc->offset = 0;
1204 
1205 	   if( list_empty(&dsc->dirObj->variant.directoryVariant.children)){
1206 	   	dsc->nextReturn = NULL;
1207 	   } else {
1208 	      	dsc->nextReturn = list_entry(dsc->dirObj->variant.directoryVariant.children.next,
1209 						yaffs_Object,siblings);
1210 	   }
1211 	} else {
1212 		/* Hey someone isn't playing nice! */
1213 	}
1214 }
1215 
1216 static void yaffsfs_DirAdvance(yaffsfs_DirectorySearchContext *dsc)
1217 {
1218 	if(dsc &&
1219 	   dsc->dirObj &&
1220 	   dsc->dirObj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY){
1221 
1222 	   if( dsc->nextReturn == NULL ||
1223 	       list_empty(&dsc->dirObj->variant.directoryVariant.children)){
1224 	   	dsc->nextReturn = NULL;
1225 	   } else {
1226 		   struct list_head *next = dsc->nextReturn->siblings.next;
1227 
1228 		   if( next == &dsc->dirObj->variant.directoryVariant.children)
1229 	   		dsc->nextReturn = NULL; /* end of list */
1230 	   	   else
1231 		   	dsc->nextReturn = list_entry(next,yaffs_Object,siblings);
1232 	   }
1233 	} else {
1234 		/* Hey someone isn't playing nice! */
1235 	}
1236 }
1237 
1238 static void yaffsfs_RemoveObjectCallback(yaffs_Object *obj)
1239 {
1240 
1241 	struct list_head *i;
1242 	yaffsfs_DirectorySearchContext *dsc;
1243 
1244 	/* if search contexts not initilised then skip */
1245 	if(!search_contexts.next)
1246 		return;
1247 
1248 	/* Iteratethrough the directory search contexts.
1249 	 * If any are the one being removed, then advance the dsc to
1250 	 * the next one to prevent a hanging ptr.
1251 	 */
1252 	 list_for_each(i, &search_contexts) {
1253 		if (i) {
1254 			dsc = list_entry(i, yaffsfs_DirectorySearchContext,others);
1255 			if(dsc->nextReturn == obj)
1256 				yaffsfs_DirAdvance(dsc);
1257 		}
1258 	}
1259 
1260 }
1261 
1262 yaffs_DIR *yaffs_opendir(const char *dirname)
1263 {
1264 	yaffs_DIR *dir = NULL;
1265  	yaffs_Object *obj = NULL;
1266 	yaffsfs_DirectorySearchContext *dsc = NULL;
1267 
1268 	yaffsfs_Lock();
1269 
1270 	obj = yaffsfs_FindObject(NULL,dirname,0);
1271 
1272 	if(obj && obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
1273 	{
1274 
1275 		dsc = YMALLOC(sizeof(yaffsfs_DirectorySearchContext));
1276 		dir = (yaffs_DIR *)dsc;
1277 		if(dsc)
1278 		{
1279 			memset(dsc,0,sizeof(yaffsfs_DirectorySearchContext));
1280 			dsc->magic = YAFFS_MAGIC;
1281 			dsc->dirObj = obj;
1282 			strncpy(dsc->name,dirname,NAME_MAX);
1283 			INIT_LIST_HEAD(&dsc->others);
1284 
1285 			if(!search_contexts.next)
1286 				INIT_LIST_HEAD(&search_contexts);
1287 
1288 			list_add(&dsc->others,&search_contexts);
1289 			yaffsfs_SetDirRewound(dsc);		}
1290 
1291 	}
1292 
1293 	yaffsfs_Unlock();
1294 
1295 	return dir;
1296 }
1297 
1298 struct yaffs_dirent *yaffs_readdir(yaffs_DIR *dirp)
1299 {
1300 	yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
1301 	struct yaffs_dirent *retVal = NULL;
1302 
1303 	yaffsfs_Lock();
1304 
1305 	if(dsc && dsc->magic == YAFFS_MAGIC){
1306 		yaffsfs_SetError(0);
1307 		if(dsc->nextReturn){
1308 			dsc->de.d_ino = yaffs_GetEquivalentObject(dsc->nextReturn)->objectId;
1309 			dsc->de.d_dont_use = (unsigned)dsc->nextReturn;
1310 			dsc->de.d_off = dsc->offset++;
1311 			yaffs_GetObjectName(dsc->nextReturn,dsc->de.d_name,NAME_MAX);
1312 			if(strlen(dsc->de.d_name) == 0)
1313 			{
1314 				// this should not happen!
1315 				strcpy(dsc->de.d_name,"zz");
1316 			}
1317 			dsc->de.d_reclen = sizeof(struct yaffs_dirent);
1318 			retVal = &dsc->de;
1319 			yaffsfs_DirAdvance(dsc);
1320 		} else
1321 			retVal = NULL;
1322 	}
1323 	else
1324 	{
1325 		yaffsfs_SetError(-EBADF);
1326 	}
1327 
1328 	yaffsfs_Unlock();
1329 
1330 	return retVal;
1331 
1332 }
1333 
1334 
1335 void yaffs_rewinddir(yaffs_DIR *dirp)
1336 {
1337 	yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
1338 
1339 	yaffsfs_Lock();
1340 
1341 	yaffsfs_SetDirRewound(dsc);
1342 
1343 	yaffsfs_Unlock();
1344 }
1345 
1346 
1347 int yaffs_closedir(yaffs_DIR *dirp)
1348 {
1349 	yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
1350 
1351 	yaffsfs_Lock();
1352 	dsc->magic = 0;
1353 	list_del(&dsc->others); /* unhook from list */
1354 	YFREE(dsc);
1355 	yaffsfs_Unlock();
1356 	return 0;
1357 }
1358 
1359 // end of directory stuff
1360 
1361 
1362 int yaffs_symlink(const char *oldpath, const char *newpath)
1363 {
1364 	yaffs_Object *parent = NULL;
1365 	yaffs_Object *obj;
1366 	char *name;
1367 	int retVal= -1;
1368 	int mode = 0; // ignore for now
1369 
1370 	yaffsfs_Lock();
1371 	parent = yaffsfs_FindDirectory(NULL,newpath,&name,0);
1372 	obj = yaffs_MknodSymLink(parent,name,mode,0,0,oldpath);
1373 	if(obj)
1374 	{
1375 		retVal = 0;
1376 	}
1377 	else
1378 	{
1379 		yaffsfs_SetError(-ENOSPC); // just assume no space for now
1380 		retVal = -1;
1381 	}
1382 
1383 	yaffsfs_Unlock();
1384 
1385 	return retVal;
1386 
1387 }
1388 
1389 int yaffs_readlink(const char *path, char *buf, int bufsiz)
1390 {
1391 	yaffs_Object *obj = NULL;
1392 	int retVal;
1393 
1394 
1395 	yaffsfs_Lock();
1396 
1397 	obj = yaffsfs_FindObject(NULL,path,0);
1398 
1399 	if(!obj)
1400 	{
1401 		yaffsfs_SetError(-ENOENT);
1402 		retVal = -1;
1403 	}
1404 	else if(obj->variantType != YAFFS_OBJECT_TYPE_SYMLINK)
1405 	{
1406 		yaffsfs_SetError(-EINVAL);
1407 		retVal = -1;
1408 	}
1409 	else
1410 	{
1411 		char *alias = obj->variant.symLinkVariant.alias;
1412 		memset(buf,0,bufsiz);
1413 		strncpy(buf,alias,bufsiz - 1);
1414 		retVal = 0;
1415 	}
1416 	yaffsfs_Unlock();
1417 	return retVal;
1418 }
1419 
1420 int yaffs_link(const char *oldpath, const char *newpath)
1421 {
1422 	// Creates a link called newpath to existing oldpath
1423 	yaffs_Object *obj = NULL;
1424 	yaffs_Object *target = NULL;
1425 	int retVal = 0;
1426 
1427 
1428 	yaffsfs_Lock();
1429 
1430 	obj = yaffsfs_FindObject(NULL,oldpath,0);
1431 	target = yaffsfs_FindObject(NULL,newpath,0);
1432 
1433 	if(!obj)
1434 	{
1435 		yaffsfs_SetError(-ENOENT);
1436 		retVal = -1;
1437 	}
1438 	else if(target)
1439 	{
1440 		yaffsfs_SetError(-EEXIST);
1441 		retVal = -1;
1442 	}
1443 	else
1444 	{
1445 		yaffs_Object *newdir = NULL;
1446 		yaffs_Object *link = NULL;
1447 
1448 		char *newname;
1449 
1450 		newdir = yaffsfs_FindDirectory(NULL,newpath,&newname,0);
1451 
1452 		if(!newdir)
1453 		{
1454 			yaffsfs_SetError(-ENOTDIR);
1455 			retVal = -1;
1456 		}
1457 		else if(newdir->myDev != obj->myDev)
1458 		{
1459 			yaffsfs_SetError(-EXDEV);
1460 			retVal = -1;
1461 		}
1462 		if(newdir && strlen(newname) > 0)
1463 		{
1464 			link = yaffs_Link(newdir,newname,obj);
1465 			if(link)
1466 				retVal = 0;
1467 			else
1468 			{
1469 				yaffsfs_SetError(-ENOSPC);
1470 				retVal = -1;
1471 			}
1472 
1473 		}
1474 	}
1475 	yaffsfs_Unlock();
1476 
1477 	return retVal;
1478 }
1479 
1480 int yaffs_mknod(const char *pathname, mode_t mode, dev_t dev);
1481 
1482 int yaffs_DumpDevStruct(const char *path)
1483 {
1484 	char *rest;
1485 
1486 	yaffs_Object *obj = yaffsfs_FindRoot(path,&rest);
1487 
1488 	if(obj)
1489 	{
1490 		yaffs_Device *dev = obj->myDev;
1491 
1492 		printf("\n"
1493 			   "nPageWrites.......... %d\n"
1494 			   "nPageReads........... %d\n"
1495 			   "nBlockErasures....... %d\n"
1496 			   "nGCCopies............ %d\n"
1497 			   "garbageCollections... %d\n"
1498 			   "passiveGarbageColl'ns %d\n"
1499 			   "\n",
1500 				dev->nPageWrites,
1501 				dev->nPageReads,
1502 				dev->nBlockErasures,
1503 				dev->nGCCopies,
1504 				dev->garbageCollections,
1505 				dev->passiveGarbageCollections
1506 		);
1507 
1508 	}
1509 	return 0;
1510 }
1511