blob: f62c952ddcc9d1c8b8a27307f799c3483014cffe [file] [log] [blame]
William Juul0e8cc8b2007-11-15 11:13:05 +01001/*
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
William Juul90ef1172007-11-15 12:23:57 +010014/* XXX U-BOOT XXX */
15#include <common.h>
16#include <malloc.h>
17
William Juul0e8cc8b2007-11-15 11:13:05 +010018#include "yaffsfs.h"
19#include "yaffs_guts.h"
20#include "yaffscfg.h"
William Juul0e8cc8b2007-11-15 11:13:05 +010021#include "yportenv.h"
22
William Juul90ef1172007-11-15 12:23:57 +010023/* XXX U-BOOT XXX */
24#if 0
25#include <string.h> // for memset
26#endif
27
William Juul0e8cc8b2007-11-15 11:13:05 +010028#define YAFFSFS_MAX_SYMLINK_DEREFERENCES 5
29
30#ifndef NULL
31#define NULL ((void *)0)
32#endif
33
34
35const 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
38static yaffsfs_DeviceConfiguration *yaffsfs_configurationList;
39
40
41/* Some forward references */
42static yaffs_Object *yaffsfs_FindObject(yaffs_Object *relativeDirectory, const char *path, int symDepth);
43static void yaffsfs_RemoveObjectCallback(yaffs_Object *obj);
44
45
46// Handle management.
47//
48
49
50unsigned int yaffs_wr_attempts;
51
52typedef 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
63static yaffsfs_Handle yaffsfs_handle[YAFFSFS_N_HANDLES];
64
65// yaffsfs_InitHandle
66/// Inilitalise handles on start-up.
67//
68static 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
79yaffsfs_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
89yaffs_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
106static 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//
131static 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
148int 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
159static 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
200static 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
213static 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"
239static 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
322static 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//
329static 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
346int 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
487int 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
520int 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
581int 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
633int 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
660off_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
715int 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}
758int yaffs_rmdir(const char *path)
759{
760 return yaffsfs_DoUnlink(path,1);
761}
762
763int yaffs_unlink(const char *path)
764{
765 return yaffsfs_DoUnlink(path,0);
766}
767
768int 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
827static 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
870static 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
900int yaffs_stat(const char *path, struct yaffs_stat *buf)
901{
902 return yaffsfs_DoStatOrLStat(path,buf,0);
903}
904
905int yaffs_lstat(const char *path, struct yaffs_stat *buf)
906{
907 return yaffsfs_DoStatOrLStat(path,buf,1);
908}
909
910int 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
934static int yaffsfs_DoChMod(yaffs_Object *obj,mode_t mode)
935{
William Juul90ef1172007-11-15 12:23:57 +0100936 int result = YAFFS_FAIL;
William Juul0e8cc8b2007-11-15 11:13:05 +0100937
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
954int 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
980int 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
1005int 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
1031int 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
1071int 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
1127loff_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
1152void 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 }
William Juul0e8cc8b2007-11-15 11:13:05 +01001169}
1170
1171
1172//
1173// Directory search stuff.
1174
1175//
1176// Directory search context
1177//
1178// NB this is an opaque structure.
1179
1180
1181typedef 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
1194static struct list_head search_contexts;
1195
1196
1197static 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
1216static 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
1238static 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
1262yaffs_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
1298struct 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
1335void 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
1347int 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
1362int 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
1389int 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
1420int 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
1480int yaffs_mknod(const char *pathname, mode_t mode, dev_t dev);
1481
1482int 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}