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