2 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
4 * Copyright (C) 2002-2010 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
7 * Created by Charles Manning <charles@aleph1.co.uk>
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.
15 #include "yaffs_guts.h"
18 #include "yaffs_trace.h"
20 #include <string.h> // for memset
22 #define YAFFSFS_MAX_SYMLINK_DEREFERENCES 5
25 #define NULL ((void *)0)
29 /* YAFFSFS_RW_SIZE must be a power of 2 */
30 #define YAFFSFS_RW_SHIFT (13)
31 #define YAFFSFS_RW_SIZE (1<<YAFFSFS_RW_SHIFT)
34 const char *yaffsfs_c_version="$Id: yaffsfs.c,v 1.35 2010-02-25 22:38:03 charles Exp $";
36 // configurationList is the list of devices that are supported
37 static yaffsfs_DeviceConfiguration *yaffsfs_configurationList;
40 /* Some forward references */
41 static yaffs_Object *yaffsfs_FindObject(yaffs_Object *relativeDirectory, const YCHAR *path, int symDepth);
42 static void yaffsfs_RemoveObjectCallback(yaffs_Object *obj);
49 unsigned int yaffs_wr_attempts;
57 __u8 readOnly:1; // this handle is read only
58 __u8 append:1; // append only
59 int inodeId:13; // the object
60 int useCount:16; // Use count for this handle
61 __u32 position; // current position in file
64 static yaffsfs_Inode yaffsfs_inode[YAFFSFS_N_HANDLES];
65 static yaffsfs_Handle yaffsfs_handle[YAFFSFS_N_HANDLES];
68 /// Inilitalise handles on start-up.
70 static int yaffsfs_InitHandles(void)
73 memset(yaffsfs_inode,0,sizeof(yaffsfs_inode));
74 memset(yaffsfs_handle,0,sizeof(yaffsfs_handle));
75 for(i = 0; i < YAFFSFS_N_HANDLES; i++)
76 yaffsfs_handle[i].inodeId = -1;
81 yaffsfs_Handle *yaffsfs_GetHandlePointer(int h)
83 if(h < 0 || h >= YAFFSFS_N_HANDLES)
86 return &yaffsfs_handle[h];
89 yaffsfs_Inode *yaffsfs_GetInodePointer(int handle)
91 yaffsfs_Handle *h = yaffsfs_GetHandlePointer(handle);
93 if(h && h->useCount > 0 && h->inodeId >= 0 && h->inodeId < YAFFSFS_N_HANDLES)
94 return &yaffsfs_inode[h->inodeId];
99 yaffs_Object *yaffsfs_GetHandleObject(int handle)
101 yaffsfs_Inode *in = yaffsfs_GetInodePointer(handle);
109 //yaffsfs_GetInodeIdForObject
110 // Grab an inode entry when opening a new inode.
113 static int yaffsfs_GetInodeIdForObject(yaffs_Object *obj)
117 yaffsfs_Inode *in = NULL;
120 obj = yaffs_GetEquivalentObject(obj);
122 /* Look for it. If we can't find it then make one */
123 for(i = 0; i < YAFFSFS_N_HANDLES && ret < 0; i++){
124 if(yaffsfs_inode[i].iObj == obj)
128 for(i = 0; i < YAFFSFS_N_HANDLES && ret < 0; i++){
129 if(!yaffsfs_inode[i].iObj)
135 in = &yaffsfs_inode[ret];
146 static void yaffsfs_ReleaseInode(yaffsfs_Inode *in)
153 yaffs_DeleteObject(obj);
160 static void yaffsfs_PutInode(int inodeId)
162 if(inodeId >= 0 && inodeId < YAFFSFS_N_HANDLES){
163 yaffsfs_Inode *in = & yaffsfs_inode[inodeId];
166 yaffsfs_ReleaseInode(in);
172 // Grab a handle (when opening a file)
175 static int yaffsfs_GetNewHandle(void)
180 for(i = 0; i < YAFFSFS_N_HANDLES; i++){
181 h = yaffsfs_GetHandlePointer(i);
183 // todo bug: should never happen
186 memset(h,0,sizeof(yaffsfs_Handle));
196 // Increase use of handle when reading/writing a file
197 static int yaffsfs_GetHandle(int handle)
199 yaffsfs_Handle *h = yaffsfs_GetHandlePointer(handle);
201 if(h && h->useCount > 0){
208 // Let go of a handle when closing a file or aborting an open or
209 // ending a read or write.
211 static int yaffsfs_PutHandle(int handle)
213 yaffsfs_Handle *h = yaffsfs_GetHandlePointer(handle);
215 if(h && h->useCount > 0){
219 yaffsfs_PutInode(h->inodeId);
230 // Stuff to search for a directory from a path
233 int yaffsfs_Match(YCHAR a, YCHAR b)
239 int yaffsfs_IsPathDivider(YCHAR ch)
241 YCHAR *str = YAFFS_PATH_DIVIDERS;
252 // yaffsfs_FindDevice
254 // Scan the configuration list to find the root.
255 // Curveballs: Should match paths that end in '/' too
256 // Curveball2 Might have "/x/ and "/x/y". Need to return the longest match
257 static yaffs_Device *yaffsfs_FindDevice(const YCHAR *path, YCHAR **restOfPath)
259 yaffsfs_DeviceConfiguration *cfg = yaffsfs_configurationList;
260 const YCHAR *leftOver;
262 yaffs_Device *retval = NULL;
264 int longestMatch = -1;
267 // Check all configs, choose the one that:
268 // 1) Actually matches a prefix (ie /a amd /abc will not match
269 // 2) Matches the longest.
270 while(cfg && cfg->prefix && cfg->dev){
277 while(matching && *p && *leftOver){
279 while(yaffsfs_IsPathDivider(*p))
283 while(yaffsfs_IsPathDivider(*leftOver))
286 // Now match the text part
288 *p && !yaffsfs_IsPathDivider(*p) &&
289 *leftOver && !yaffsfs_IsPathDivider(*leftOver)){
290 if(yaffsfs_Match(*p,*leftOver)){
300 // Skip over any /s in leftOver
301 while(yaffsfs_IsPathDivider(*leftOver))
305 if( matching && (thisMatchLength > longestMatch)){
307 *restOfPath = (YCHAR *)leftOver;
309 longestMatch = thisMatchLength;
318 static yaffs_Device *yaffsfs_FindDevice(const YCHAR *path, YCHAR **restOfPath)
320 yaffsfs_DeviceConfiguration *cfg = yaffsfs_configurationList;
321 const YCHAR *leftOver;
323 yaffs_Device *retval = NULL;
325 int longestMatch = -1;
327 // Check all configs, choose the one that:
328 // 1) Actually matches a prefix (ie /a amd /abc will not match
329 // 2) Matches the longest.
330 while(cfg && cfg->prefix && cfg->dev){
335 while(*p && //unmatched part of prefix
336 !(yaffsfs_IsPathDivider(*p) && (p[1] == 0)) && // the rest of the prefix is not / (to catch / at end)
338 yaffsfs_Match(*p,*leftOver)){
345 if((!*p || (yaffsfs_IsPathDivider(*p) && (p[1] == 0))) && // end of prefix
346 (!*leftOver || yaffsfs_IsPathDivider(*leftOver)) && // no more in this path name part
347 (thisMatchLength > longestMatch)){
349 *restOfPath = (YCHAR *)leftOver;
351 longestMatch = thisMatchLength;
359 static yaffs_Object *yaffsfs_FindRoot(const YCHAR *path, YCHAR **restOfPath)
364 dev= yaffsfs_FindDevice(path,restOfPath);
365 if(dev && dev->isMounted){
371 static yaffs_Object *yaffsfs_FollowLink(yaffs_Object *obj,int symDepth)
374 while(obj && obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK){
375 YCHAR *alias = obj->variant.symLinkVariant.alias;
377 if(yaffsfs_IsPathDivider(*alias))
378 // Starts with a /, need to scan from root up
379 obj = yaffsfs_FindObject(NULL,alias,symDepth++);
381 // Relative to here, so use the parent of the symlink as a start
382 obj = yaffsfs_FindObject(obj->parent,alias,symDepth++);
388 // yaffsfs_FindDirectory
389 // Parse a path to determine the directory and the name within the directory.
391 // eg. "/data/xx/ff" --> puts name="ff" and returns the directory "/data/xx"
392 static yaffs_Object *yaffsfs_DoFindDirectory(yaffs_Object *startDir,const YCHAR *path,YCHAR **name,int symDepth)
396 YCHAR str[YAFFS_MAX_NAME_LENGTH+1];
399 if(symDepth > YAFFSFS_MAX_SYMLINK_DEREFERENCES)
404 restOfPath = (YCHAR *)path;
407 dir = yaffsfs_FindRoot(path,&restOfPath);
411 // curve ball: also throw away surplus '/'
412 // eg. "/ram/x////ff" gets treated the same as "/ram/x/ff"
413 while(yaffsfs_IsPathDivider(*restOfPath))
414 restOfPath++; // get rid of '/'
419 while(*restOfPath && !yaffsfs_IsPathDivider(*restOfPath)){
420 if (i < YAFFS_MAX_NAME_LENGTH){
421 str[i] = *restOfPath;
429 // got to the end of the string
432 if(yaffs_strcmp(str,_Y(".")) == 0)
436 else if(yaffs_strcmp(str,_Y("..")) == 0)
439 dir = yaffs_FindObjectByName(dir,str);
441 while(dir && dir->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
442 dir = yaffsfs_FollowLink(dir,symDepth);
445 if(dir && dir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
450 // directory did not exist.
454 static yaffs_Object *yaffsfs_FindDirectory(yaffs_Object *relativeDirectory,const YCHAR *path,YCHAR **name,int symDepth)
456 return yaffsfs_DoFindDirectory(relativeDirectory,path,name,symDepth);
459 // yaffsfs_FindObject turns a path for an existing object into the object
461 static yaffs_Object *yaffsfs_FindObject(yaffs_Object *relativeDirectory, const YCHAR *path,int symDepth)
466 dir = yaffsfs_FindDirectory(relativeDirectory,path,&name,symDepth);
469 return yaffs_FindObjectByName(dir,name);
475 int yaffs_dup(int fd)
478 yaffsfs_Handle *oldPtr = NULL;
479 yaffsfs_Handle *newPtr = NULL;
483 oldPtr = yaffsfs_GetHandlePointer(fd);
484 if(oldPtr && oldPtr->useCount > 0)
485 newHandle = yaffsfs_GetNewHandle();
487 newPtr = yaffsfs_GetHandlePointer(newHandle);
495 yaffsfs_SetError(-EBADF);
497 yaffsfs_SetError(-ENOMEM);
503 int yaffs_open(const YCHAR *path, int oflag, int mode)
505 yaffs_Object *obj = NULL;
506 yaffs_Object *dir = NULL;
509 yaffsfs_Handle *h = NULL;
512 int errorReported = 0;
514 /* O_EXCL only has meaning if O_CREAT is specified */
515 if(!(oflag & O_CREAT))
518 /* O_TRUNC has no meaning if (O_CREAT | O_EXCL) is specified */
519 if( (oflag & O_CREAT) & (oflag & O_EXCL))
522 /* Todo: Are there any more flag combos to sanitise ? */
527 handle = yaffsfs_GetNewHandle();
531 h = yaffsfs_GetHandlePointer(handle);
534 // try to find the exisiting object
535 obj = yaffsfs_FindObject(NULL,path,0);
537 if(obj && obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
538 obj = yaffsfs_FollowLink(obj,symDepth++);
541 obj = yaffs_GetEquivalentObject(obj);
543 if(obj && obj->variantType != YAFFS_OBJECT_TYPE_FILE)
548 /* The file already exists */
550 // Open should fail if O_CREAT and O_EXCL are specified since
552 if((oflag & O_EXCL) && (oflag & O_CREAT)){
554 yaffsfs_SetError(-EEXIST);
558 // Check file permissions
559 if( (oflag & (O_RDWR | O_WRONLY)) == 0 && // ie O_RDONLY
560 !(obj->yst_mode & S_IREAD))
563 if( (oflag & O_RDWR) &&
564 !(obj->yst_mode & S_IREAD))
567 if( (oflag & (O_RDWR | O_WRONLY)) &&
568 !(obj->yst_mode & S_IWRITE))
571 } else if((oflag & O_CREAT)) {
572 // Let's see if we can create this file
573 dir = yaffsfs_FindDirectory(NULL,path,&name,0);
574 if(dir && dir->myDev->readOnly){
575 yaffsfs_SetError(-EINVAL);
578 obj = yaffs_MknodFile(dir,name,mode,0,0);
580 yaffsfs_SetError(-ENOTDIR);
585 if(obj && !openDenied) {
586 int inodeId = yaffsfs_GetInodeIdForObject(obj);
590 * Todo: Fix any problem if inodes run out, though that
591 * can't happen if the number of inode items >= number of handles.
595 h->inodeId = inodeId;
596 h->readOnly = (oflag & (O_WRONLY | O_RDWR)) ? 0 : 1;
597 h->append = (oflag & O_APPEND) ? 1 : 0;
600 /* Hook inode to object */
601 obj->myInode = (void*) &yaffsfs_inode[inodeId];
603 if((oflag & O_TRUNC) && !h->readOnly)
604 yaffs_ResizeFile(obj,0);
606 yaffsfs_PutHandle(handle);
608 yaffsfs_SetError(-EACCES);
620 int yaffs_Dofsync(int fd,int datasync)
622 yaffsfs_Handle *h = NULL;
627 h = yaffsfs_GetHandlePointer(fd);
629 if(h && h->useCount > 0)
631 yaffs_FlushFile(yaffsfs_inode[h->inodeId].iObj,1,datasync);
634 yaffsfs_SetError(-EBADF);
643 int yaffs_fsync(int fd)
645 return yaffs_Dofsync(fd,0);
648 int yaffs_flush(int fd)
650 return yaffs_fsync(fd);
653 int yaffs_fdatasync(int fd)
655 return yaffs_Dofsync(fd,1);
658 int yaffs_close(int fd)
660 yaffsfs_Handle *h = NULL;
665 h = yaffsfs_GetHandlePointer(fd);
667 if(h && h->useCount > 0) {
669 yaffs_FlushFile(yaffsfs_inode[h->inodeId].iObj,1,0);
670 yaffsfs_PutHandle(fd);
674 yaffsfs_SetError(-EBADF);
685 int yaffsfs_do_read(int fd, void *vbuf, unsigned int nbyte, int isPread, int offset)
687 yaffsfs_Handle *h = NULL;
688 yaffs_Object *obj = NULL;
694 unsigned int maxRead;
695 __u8 *buf = (__u8 *)vbuf;
698 h = yaffsfs_GetHandlePointer(fd);
699 obj = yaffsfs_GetHandleObject(fd);
703 yaffsfs_SetError(-EBADF);
705 } else if( h && obj){
709 startPos = h->position;
713 if(yaffs_GetObjectFileLength(obj) > pos)
714 maxRead = yaffs_GetObjectFileLength(obj) - pos;
722 yaffsfs_GetHandle(fd);
725 nToRead = YAFFSFS_RW_SIZE - (pos & (YAFFSFS_RW_SIZE -1));
728 nRead = yaffs_ReadDataFromFile(obj,buf,pos,nToRead);
739 nbyte = 0; /* no more to read */
749 yaffsfs_PutHandle(fd);
753 h->position = startPos + totalRead;
763 return (totalRead >= 0) ? totalRead : -1;
767 int yaffs_read(int fd, void *buf, unsigned int nbyte)
769 return yaffsfs_do_read(fd, buf, nbyte, 0, 0);
772 int yaffs_pread(int fd, void *buf, unsigned int nbyte, unsigned int offset)
774 return yaffsfs_do_read(fd, buf, nbyte, 1, offset);
777 int yaffsfs_do_write(int fd, const void *vbuf, unsigned int nbyte, int isPwrite, int offset)
779 yaffsfs_Handle *h = NULL;
780 yaffs_Object *obj = NULL;
784 int totalWritten = 0;
785 int writeThrough = 0;
787 const __u8 *buf = (const __u8 *)vbuf;
790 h = yaffsfs_GetHandlePointer(fd);
791 obj = yaffsfs_GetHandleObject(fd);
795 yaffsfs_SetError(-EBADF);
797 } else if( h && obj && (h->readOnly || obj->myDev->readOnly)){
798 yaffsfs_SetError(-EINVAL);
800 } else if( h && obj){
804 startPos = yaffs_GetObjectFileLength(obj);
806 startPos = h->position;
808 yaffsfs_GetHandle(fd);
811 nToWrite = YAFFSFS_RW_SIZE - (pos & (YAFFSFS_RW_SIZE -1));
815 nWritten = yaffs_WriteDataToFile(obj,buf,pos,nToWrite,writeThrough);
817 totalWritten += nWritten;
822 if(nWritten == nToWrite)
827 if(nWritten < 1 && totalWritten < 1){
828 yaffsfs_SetError(-ENOSPC);
838 yaffsfs_PutHandle(fd);
842 h->position = startPos + totalWritten;
851 return (totalWritten >= 0) ? totalWritten : -1;
854 int yaffs_write(int fd, const void *buf, unsigned int nbyte)
856 return yaffsfs_do_write(fd, buf, nbyte, 0, 0);
859 int yaffs_pwrite(int fd, const void *buf, unsigned int nbyte, unsigned int offset)
861 return yaffsfs_do_write(fd, buf, nbyte, 1, offset);
865 int yaffs_truncate(const YCHAR *path,off_t newSize)
867 yaffs_Object *obj = NULL;
868 int result = YAFFS_FAIL;
872 obj = yaffsfs_FindObject(NULL,path,0);
874 obj = yaffs_GetEquivalentObject(obj);
877 yaffsfs_SetError(-ENOENT);
878 else if(obj->variantType != YAFFS_OBJECT_TYPE_FILE)
879 yaffsfs_SetError(-EISDIR);
880 else if(obj->myDev->readOnly)
881 yaffsfs_SetError(-EINVAL);
883 result = yaffs_ResizeFile(obj,newSize);
888 return (result) ? 0 : -1;
891 int yaffs_ftruncate(int fd, off_t newSize)
893 yaffsfs_Handle *h = NULL;
894 yaffs_Object *obj = NULL;
898 h = yaffsfs_GetHandlePointer(fd);
899 obj = yaffsfs_GetHandleObject(fd);
903 yaffsfs_SetError(-EBADF);
904 else if(obj->myDev->readOnly)
905 yaffsfs_SetError(-EINVAL);
908 result = yaffs_ResizeFile(obj,newSize);
912 return (result) ? 0 : -1;
916 off_t yaffs_lseek(int fd, off_t offset, int whence)
918 yaffsfs_Handle *h = NULL;
919 yaffs_Object *obj = NULL;
924 h = yaffsfs_GetHandlePointer(fd);
925 obj = yaffsfs_GetHandleObject(fd);
929 yaffsfs_SetError(-EBADF);
930 else if(whence == SEEK_SET){
934 else if(whence == SEEK_CUR) {
935 if( (h->position + offset) >= 0)
936 pos = (h->position + offset);
938 else if(whence == SEEK_END) {
939 fSize = yaffs_GetObjectFileLength(obj);
940 if(fSize >= 0 && (fSize + offset) >= 0)
941 pos = fSize + offset;
957 int yaffsfs_DoUnlink(const YCHAR *path,int isDirectory)
959 yaffs_Object *dir = NULL;
960 yaffs_Object *obj = NULL;
962 int result = YAFFS_FAIL;
966 obj = yaffsfs_FindObject(NULL,path,0);
967 dir = yaffsfs_FindDirectory(NULL,path,&name,0);
969 yaffsfs_SetError(-ENOTDIR);
971 yaffsfs_SetError(-ENOENT);
972 else if(obj->myDev->readOnly)
973 yaffsfs_SetError(-EINVAL);
974 else if(!isDirectory && obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
975 yaffsfs_SetError(-EISDIR);
976 else if(isDirectory && obj->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
977 yaffsfs_SetError(-ENOTDIR);
979 result = yaffs_Unlink(dir,name);
981 if(result == YAFFS_FAIL && isDirectory)
982 yaffsfs_SetError(-ENOTEMPTY);
989 return (result == YAFFS_FAIL) ? -1 : 0;
993 int yaffs_rmdir(const YCHAR *path)
995 return yaffsfs_DoUnlink(path,1);
998 int yaffs_unlink(const YCHAR *path)
1000 return yaffsfs_DoUnlink(path,0);
1003 int yaffs_rename(const YCHAR *oldPath, const YCHAR *newPath)
1005 yaffs_Object *olddir = NULL;
1006 yaffs_Object *newdir = NULL;
1007 yaffs_Object *obj = NULL;
1010 int result= YAFFS_FAIL;
1011 int renameAllowed = 1;
1015 olddir = yaffsfs_FindDirectory(NULL,oldPath,&oldname,0);
1016 newdir = yaffsfs_FindDirectory(NULL,newPath,&newname,0);
1017 obj = yaffsfs_FindObject(NULL,oldPath,0);
1019 if(!olddir || !newdir || !obj) {
1021 yaffsfs_SetError(-EBADF);
1023 } else if(obj->myDev->readOnly){
1024 yaffsfs_SetError(-EINVAL);
1026 } else if(olddir->myDev != newdir->myDev) {
1027 // oops must be on same device
1029 yaffsfs_SetError(-EXDEV);
1031 } else if(obj && obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) {
1032 // It is a directory, check that it is not being renamed to
1033 // being its own decendent.
1034 // Do this by tracing from the new directory back to the root, checking for obj
1036 yaffs_Object *xx = newdir;
1038 while( renameAllowed && xx){
1044 yaffsfs_SetError(-EACCES);
1048 result = yaffs_RenameObject(olddir,oldname,newdir,newname);
1052 return (result == YAFFS_FAIL) ? -1 : 0;
1056 static int yaffsfs_DoStat(yaffs_Object *obj,struct yaffs_stat *buf)
1061 obj = yaffs_GetEquivalentObject(obj);
1064 buf->st_dev = (int)obj->myDev->context;
1065 buf->st_ino = obj->objectId;
1066 buf->st_mode = obj->yst_mode & ~S_IFMT; // clear out file type bits
1068 if(obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
1069 buf->st_mode |= S_IFDIR;
1070 else if(obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
1071 buf->st_mode |= S_IFLNK;
1072 else if(obj->variantType == YAFFS_OBJECT_TYPE_FILE)
1073 buf->st_mode |= S_IFREG;
1075 buf->st_nlink = yaffs_GetObjectLinkCount(obj);
1078 buf->st_rdev = obj->yst_rdev;
1079 buf->st_size = yaffs_GetObjectFileLength(obj);
1080 buf->st_blksize = obj->myDev->nDataBytesPerChunk;
1081 buf->st_blocks = (buf->st_size + buf->st_blksize -1)/buf->st_blksize;
1082 #if CONFIG_YAFFS_WINCE
1083 buf->yst_wince_atime[0] = obj->win_atime[0];
1084 buf->yst_wince_atime[1] = obj->win_atime[1];
1085 buf->yst_wince_ctime[0] = obj->win_ctime[0];
1086 buf->yst_wince_ctime[1] = obj->win_ctime[1];
1087 buf->yst_wince_mtime[0] = obj->win_mtime[0];
1088 buf->yst_wince_mtime[1] = obj->win_mtime[1];
1090 buf->yst_atime = obj->yst_atime;
1091 buf->yst_ctime = obj->yst_ctime;
1092 buf->yst_mtime = obj->yst_mtime;
1099 static int yaffsfs_DoStatOrLStat(const YCHAR *path, struct yaffs_stat *buf,int doLStat)
1106 obj = yaffsfs_FindObject(NULL,path,0);
1109 obj = yaffsfs_FollowLink(obj,0);
1112 retVal = yaffsfs_DoStat(obj,buf);
1114 // todo error not found
1115 yaffsfs_SetError(-ENOENT);
1123 int yaffs_stat(const YCHAR *path, struct yaffs_stat *buf)
1125 return yaffsfs_DoStatOrLStat(path,buf,0);
1128 int yaffs_lstat(const YCHAR *path, struct yaffs_stat *buf)
1130 return yaffsfs_DoStatOrLStat(path,buf,1);
1133 int yaffs_fstat(int fd, struct yaffs_stat *buf)
1140 obj = yaffsfs_GetHandleObject(fd);
1143 retVal = yaffsfs_DoStat(obj,buf);
1146 yaffsfs_SetError(-EBADF);
1153 #ifdef CONFIG_YAFFS_WINCE
1154 int yaffs_get_wince_times(int fd, unsigned *wctime, unsigned *watime, unsigned *wmtime)
1161 obj = yaffsfs_GetHandleObject(fd);
1166 wctime[0] = obj->win_ctime[0];
1167 wctime[1] = obj->win_ctime[1];
1170 watime[0] = obj->win_atime[0];
1171 watime[1] = obj->win_atime[1];
1174 wmtime[0] = obj->win_mtime[0];
1175 wmtime[1] = obj->win_mtime[1];
1182 yaffsfs_SetError(-EBADF);
1190 int yaffs_set_wince_times(int fd,
1191 const unsigned *wctime,
1192 const unsigned *watime,
1193 const unsigned *wmtime)
1200 obj = yaffsfs_GetHandleObject(fd);
1205 obj->win_ctime[0] = wctime[0];
1206 obj->win_ctime[1] = wctime[1];
1209 obj->win_atime[0] = watime[0];
1210 obj->win_atime[1] = watime[1];
1213 obj->win_mtime[0] = wmtime[0];
1214 obj->win_mtime[1] = wmtime[1];
1218 result = yaffs_FlushFile(obj,0,0);
1222 yaffsfs_SetError(-EBADF);
1232 static int yaffsfs_DoChMod(yaffs_Object *obj,mode_t mode)
1237 obj = yaffs_GetEquivalentObject(obj);
1240 obj->yst_mode = mode;
1242 result = yaffs_FlushFile(obj,0,0);
1245 return result == YAFFS_OK ? 0 : -1;
1249 int yaffs_access(const YCHAR *path, int amode)
1256 obj = yaffsfs_FindObject(NULL,path,0);
1261 if((amode & R_OK) && !(obj->yst_mode & S_IREAD))
1263 if((amode & W_OK) && !(obj->yst_mode & S_IWRITE))
1265 if((amode & X_OK) && !(obj->yst_mode & S_IEXEC))
1269 yaffsfs_SetError(-EACCES);
1273 // todo error not found
1274 yaffsfs_SetError(-ENOENT);
1285 int yaffs_chmod(const YCHAR *path, mode_t mode)
1292 obj = yaffsfs_FindObject(NULL,path,0);
1295 yaffsfs_SetError(-ENOENT);
1296 else if(obj->myDev->readOnly)
1297 yaffsfs_SetError(-EINVAL);
1299 retVal = yaffsfs_DoChMod(obj,mode);
1308 int yaffs_fchmod(int fd, mode_t mode)
1315 obj = yaffsfs_GetHandleObject(fd);
1318 yaffsfs_SetError(-ENOENT);
1319 else if(obj->myDev->readOnly)
1320 yaffsfs_SetError(-EINVAL);
1322 retVal = yaffsfs_DoChMod(obj,mode);
1330 int yaffs_mkdir(const YCHAR *path, mode_t mode)
1332 yaffs_Object *parent = NULL;
1333 yaffs_Object *dir = NULL;
1338 parent = yaffsfs_FindDirectory(NULL,path,&name,0);
1339 if(parent && parent->myDev->readOnly){
1340 yaffsfs_SetError(-EINVAL);
1343 dir = yaffs_MknodDirectory(parent,name,mode,0,0);
1348 yaffsfs_SetError(-ENOENT); // missing path
1349 else if (yaffs_FindObjectByName(parent,name))
1350 yaffsfs_SetError(-EEXIST); // the name already exists
1352 yaffsfs_SetError(-ENOSPC); // just assume no space
1362 int yaffs_mount2(const YCHAR *path,int readOnly)
1365 int result=YAFFS_FAIL;
1366 yaffs_Device *dev=NULL;
1369 T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: Mounting %s" TENDSTR),path));
1372 dev = yaffsfs_FindDevice(path,&dummy);
1374 if(!dev->isMounted){
1375 dev->readOnly = readOnly ? 1 : 0;
1376 result = yaffs_GutsInitialise(dev);
1377 if(result == YAFFS_FAIL)
1378 // todo error - mount failed
1379 yaffsfs_SetError(-ENOMEM);
1380 retVal = result ? 0 : -1;
1384 //todo error - already mounted.
1385 yaffsfs_SetError(-EBUSY);
1387 // todo error - no device
1388 yaffsfs_SetError(-ENODEV);
1395 int yaffs_mount(const YCHAR *path)
1397 return yaffs_mount2(path,0);
1400 int yaffs_sync(const YCHAR *path)
1403 yaffs_Device *dev=NULL;
1407 dev = yaffsfs_FindDevice(path,&dummy);
1411 yaffs_FlushEntireDeviceCache(dev);
1412 yaffs_CheckpointSave(dev);
1416 //todo error - not mounted.
1417 yaffsfs_SetError(-EINVAL);
1420 // todo error - no device
1421 yaffsfs_SetError(-ENODEV);
1428 int yaffs_remount(const YCHAR *path, int force, int readOnly)
1431 yaffs_Device *dev=NULL;
1435 dev = yaffsfs_FindDevice(path,&dummy);
1441 yaffs_FlushEntireDeviceCache(dev);
1443 for(i = inUse = 0; i < YAFFSFS_N_HANDLES && !inUse && !force; i++){
1444 if(yaffsfs_handle[i].useCount>0 && yaffsfs_inode[yaffsfs_handle[i].inodeId].iObj->myDev == dev)
1445 inUse = 1; // the device is in use, can't unmount
1448 if(!inUse || force){
1450 yaffs_CheckpointSave(dev);
1451 dev->readOnly = readOnly ? 1 : 0;
1454 yaffsfs_SetError(-EBUSY);
1457 yaffsfs_SetError(-EINVAL);
1461 yaffsfs_SetError(-ENODEV);
1468 int yaffs_unmount2(const YCHAR *path, int force)
1471 yaffs_Device *dev=NULL;
1475 dev = yaffsfs_FindDevice(path,&dummy);
1481 yaffs_FlushEntireDeviceCache(dev);
1482 yaffs_CheckpointSave(dev);
1484 for(i = inUse = 0; i < YAFFSFS_N_HANDLES && !inUse; i++){
1485 if(yaffsfs_handle[i].useCount > 0 && yaffsfs_inode[yaffsfs_handle[i].inodeId].iObj->myDev == dev)
1486 inUse = 1; // the device is in use, can't unmount
1489 if(!inUse || force){
1490 yaffs_Deinitialise(dev);
1494 // todo error can't unmount as files are open
1495 yaffsfs_SetError(-EBUSY);
1498 //todo error - not mounted.
1499 yaffsfs_SetError(-EINVAL);
1503 // todo error - no device
1504 yaffsfs_SetError(-ENODEV);
1511 int yaffs_unmount(const YCHAR *path)
1513 return yaffs_unmount2(path,0);
1516 loff_t yaffs_freespace(const YCHAR *path)
1519 yaffs_Device *dev=NULL;
1523 dev = yaffsfs_FindDevice(path,&dummy);
1524 if(dev && dev->isMounted){
1525 retVal = yaffs_GetNumberOfFreeChunks(dev);
1526 retVal *= dev->nDataBytesPerChunk;
1529 yaffsfs_SetError(-EINVAL);
1535 loff_t yaffs_totalspace(const YCHAR *path)
1538 yaffs_Device *dev=NULL;
1542 dev = yaffsfs_FindDevice(path,&dummy);
1543 if(dev && dev->isMounted){
1544 retVal = (dev->param.endBlock - dev->param.startBlock + 1) - dev->param.nReservedBlocks;
1545 retVal *= dev->param.nChunksPerBlock;
1546 retVal *= dev->nDataBytesPerChunk;
1549 yaffsfs_SetError(-EINVAL);
1555 int yaffs_inodecount(const YCHAR *path)
1558 yaffs_Device *dev=NULL;
1562 dev = yaffsfs_FindDevice(path,&dummy);
1563 if(dev && dev->isMounted) {
1564 int nObjects = dev->nObjectsCreated - dev->nFreeObjects;
1565 if(nObjects > dev->nHardLinks)
1566 retVal = nObjects - dev->nHardLinks;
1570 yaffsfs_SetError(-EINVAL);
1578 void yaffs_initialise(yaffsfs_DeviceConfiguration *cfgList)
1581 yaffsfs_DeviceConfiguration *cfg;
1583 yaffsfs_configurationList = cfgList;
1585 yaffsfs_InitHandles();
1587 cfg = yaffsfs_configurationList;
1589 while(cfg && cfg->prefix && cfg->dev){
1590 cfg->dev->isMounted = 0;
1591 cfg->dev->param.removeObjectCallback = yaffsfs_RemoveObjectCallback;
1600 // Directory search stuff.
1603 // Directory search context
1605 // NB this is an opaque structure.
1611 yaffs_dirent de; /* directory entry being used by this dsc */
1612 YCHAR name[NAME_MAX+1]; /* name of directory being searched */
1613 yaffs_Object *dirObj; /* ptr to directory being searched */
1614 yaffs_Object *nextReturn; /* obj to be returned by next readddir */
1616 struct ylist_head others;
1617 } yaffsfs_DirectorySearchContext;
1621 static struct ylist_head search_contexts;
1624 static void yaffsfs_SetDirRewound(yaffsfs_DirectorySearchContext *dsc)
1628 dsc->dirObj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY){
1632 if( ylist_empty(&dsc->dirObj->variant.directoryVariant.children))
1633 dsc->nextReturn = NULL;
1635 dsc->nextReturn = ylist_entry(dsc->dirObj->variant.directoryVariant.children.next,
1636 yaffs_Object,siblings);
1638 /* Hey someone isn't playing nice! */
1642 static void yaffsfs_DirAdvance(yaffsfs_DirectorySearchContext *dsc)
1646 dsc->dirObj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY){
1648 if( dsc->nextReturn == NULL ||
1649 ylist_empty(&dsc->dirObj->variant.directoryVariant.children))
1650 dsc->nextReturn = NULL;
1652 struct ylist_head *next = dsc->nextReturn->siblings.next;
1654 if( next == &dsc->dirObj->variant.directoryVariant.children)
1655 dsc->nextReturn = NULL; /* end of list */
1657 dsc->nextReturn = ylist_entry(next,yaffs_Object,siblings);
1660 /* Hey someone isn't playing nice! */
1664 static void yaffsfs_RemoveObjectCallback(yaffs_Object *obj)
1667 struct ylist_head *i;
1668 yaffsfs_DirectorySearchContext *dsc;
1670 /* if search contexts not initilised then skip */
1671 if(!search_contexts.next)
1674 /* Iterate through the directory search contexts.
1675 * If any are the one being removed, then advance the dsc to
1676 * the next one to prevent a hanging ptr.
1678 ylist_for_each(i, &search_contexts) {
1680 dsc = ylist_entry(i, yaffsfs_DirectorySearchContext,others);
1681 if(dsc->nextReturn == obj)
1682 yaffsfs_DirAdvance(dsc);
1688 yaffs_DIR *yaffs_opendir(const YCHAR *dirname)
1690 yaffs_DIR *dir = NULL;
1691 yaffs_Object *obj = NULL;
1692 yaffsfs_DirectorySearchContext *dsc = NULL;
1696 obj = yaffsfs_FindObject(NULL,dirname,0);
1698 if(obj && obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY){
1700 dsc = YMALLOC(sizeof(yaffsfs_DirectorySearchContext));
1701 dir = (yaffs_DIR *)dsc;
1704 memset(dsc,0,sizeof(yaffsfs_DirectorySearchContext));
1705 dsc->magic = YAFFS_MAGIC;
1707 yaffs_strncpy(dsc->name,dirname,NAME_MAX);
1708 YINIT_LIST_HEAD(&dsc->others);
1710 if(!search_contexts.next)
1711 YINIT_LIST_HEAD(&search_contexts);
1713 ylist_add(&dsc->others,&search_contexts);
1714 yaffsfs_SetDirRewound(dsc);
1724 struct yaffs_dirent *yaffs_readdir(yaffs_DIR *dirp)
1726 yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
1727 struct yaffs_dirent *retVal = NULL;
1731 if(dsc && dsc->magic == YAFFS_MAGIC){
1732 yaffsfs_SetError(0);
1733 if(dsc->nextReturn){
1734 dsc->de.d_ino = yaffs_GetEquivalentObject(dsc->nextReturn)->objectId;
1735 dsc->de.d_dont_use = (unsigned)dsc->nextReturn;
1736 dsc->de.d_off = dsc->offset++;
1737 yaffs_GetObjectName(dsc->nextReturn,dsc->de.d_name,NAME_MAX);
1738 if(yaffs_strnlen(dsc->de.d_name,NAME_MAX+1) == 0)
1740 // this should not happen!
1741 yaffs_strcpy(dsc->de.d_name,_Y("zz"));
1743 dsc->de.d_reclen = sizeof(struct yaffs_dirent);
1745 yaffsfs_DirAdvance(dsc);
1749 yaffsfs_SetError(-EBADF);
1758 void yaffs_rewinddir(yaffs_DIR *dirp)
1760 yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
1764 yaffsfs_SetDirRewound(dsc);
1770 int yaffs_closedir(yaffs_DIR *dirp)
1772 yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
1776 ylist_del(&dsc->others); /* unhook from list */
1782 // end of directory stuff
1785 int yaffs_symlink(const YCHAR *oldpath, const YCHAR *newpath)
1787 yaffs_Object *parent = NULL;
1791 int mode = 0; // ignore for now
1794 parent = yaffsfs_FindDirectory(NULL,newpath,&name,0);
1795 if(parent && parent->myDev->readOnly)
1796 yaffsfs_SetError(-EINVAL);
1798 obj = yaffs_MknodSymLink(parent,name,mode,0,0,oldpath);
1802 yaffsfs_SetError(-ENOSPC); // just assume no space for now
1806 yaffsfs_SetError(-EINVAL);
1816 int yaffs_readlink(const YCHAR *path, YCHAR *buf, int bufsiz)
1818 yaffs_Object *obj = NULL;
1824 obj = yaffsfs_FindObject(NULL,path,0);
1827 yaffsfs_SetError(-ENOENT);
1829 } else if(obj->variantType != YAFFS_OBJECT_TYPE_SYMLINK) {
1830 yaffsfs_SetError(-EINVAL);
1833 YCHAR *alias = obj->variant.symLinkVariant.alias;
1834 memset(buf,0,bufsiz);
1835 yaffs_strncpy(buf,alias,bufsiz - 1);
1842 int yaffs_link(const YCHAR *oldpath, const YCHAR *newpath)
1844 // Creates a link called newpath to existing oldpath
1845 yaffs_Object *obj = NULL;
1846 yaffs_Object *target = NULL;
1848 int newNameLength = 0;
1853 obj = yaffsfs_FindObject(NULL,oldpath,0);
1854 target = yaffsfs_FindObject(NULL,newpath,0);
1857 yaffsfs_SetError(-ENOENT);
1859 } else if(obj->myDev->readOnly){
1860 yaffsfs_SetError(-EINVAL);
1863 yaffsfs_SetError(-EEXIST);
1866 yaffs_Object *newdir = NULL;
1867 yaffs_Object *link = NULL;
1871 newdir = yaffsfs_FindDirectory(NULL,newpath,&newname,0);
1874 yaffsfs_SetError(-ENOTDIR);
1876 }else if(newdir->myDev != obj->myDev){
1877 yaffsfs_SetError(-EXDEV);
1881 newNameLength = yaffs_strnlen(newname,YAFFS_MAX_NAME_LENGTH+1);
1883 if(newNameLength == 0){
1884 yaffsfs_SetError(-ENOENT);
1886 } else if (newNameLength > YAFFS_MAX_NAME_LENGTH){
1887 yaffsfs_SetError(-ENAMETOOLONG);
1892 link = yaffs_Link(newdir,newname,obj);
1896 yaffsfs_SetError(-ENOSPC);
1907 int yaffs_mknod(const YCHAR *pathname, mode_t mode, dev_t dev)
1912 int yaffs_DumpDevStruct(const YCHAR *path)
1917 yaffs_Object *obj = yaffsfs_FindRoot(path,&rest);
1920 yaffs_Device *dev = obj->myDev;
1923 "nPageWrites.......... %d\n"
1924 "nPageReads........... %d\n"
1925 "nBlockErasures....... %d\n"
1926 "nGCCopies............ %d\n"
1927 "garbageCollections... %d\n"
1928 "passiveGarbageColl'ns %d\n"
1932 dev->nBlockErasures,
1934 dev->garbageCollections,
1935 dev->passiveGarbageCollections