2 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
4 * Copyright (C) 2002-2011 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.
16 #include "yaffs_guts.h"
19 #include "yaffs_trace.h"
21 #define YAFFSFS_MAX_SYMLINK_DEREFERENCES 5
24 #define NULL ((void *)0)
27 /* YAFFSFS_RW_SIZE must be a power of 2 */
28 #define YAFFSFS_RW_SHIFT (13)
29 #define YAFFSFS_RW_SIZE (1<<YAFFSFS_RW_SHIFT)
31 /* Some forward references */
32 static struct yaffs_obj
*yaffsfs_FindObject(struct yaffs_obj
*relativeDirectory
,
34 int symDepth
, int getEquiv
,
35 struct yaffs_obj
**dirOut
,
36 int *notDir
, int *loop
);
38 static void yaffsfs_RemoveObjectCallback(struct yaffs_obj
*obj
);
40 unsigned int yaffs_wr_attempts
;
44 * There are open inodes in struct yaffsfs_Inode.
45 * There are open file descriptors in yaffsfs_FileDes.
46 * There are open handles in yaffsfs_FileDes.
48 * Things are structured this way to be like the Linux VFS model
49 * so that interactions with the yaffs guts calls are similar.
50 * That means more common code paths and less special code.
51 * That means better testing etc.
53 * We have 3 layers because:
54 * A handle is different than an fd because you can use dup()
55 * to create a new handle that accesses the *same* fd. The two
56 * handles will use the same offset (part of the fd). We only close
57 * down the fd when there are no more handles accessing it.
59 * More than one fd can currently access one file, but each fd
60 * has its own permsiions and offset.
63 struct yaffsfs_Inode
{
64 int count
; /* Number of handles accessing this inode */
65 struct yaffs_obj
*iObj
;
68 struct yaffsfs_FileDes
{
74 int inodeId
:12; /* Index to corresponding yaffsfs_Inode */
75 int handleCount
:10; /* Number of handles for this fd */
76 loff_t position
; /* current position in file */
79 struct yaffsfs_Handle
{
85 struct yaffsfs_DirSearchContxt
{
86 struct yaffs_dirent de
; /* directory entry */
87 YCHAR name
[NAME_MAX
+ 1]; /* name of directory being searched */
88 struct yaffs_obj
*dirObj
; /* ptr to directory being searched */
89 struct yaffs_obj
*nextReturn
; /* obj returned by next readddir */
90 struct list_head others
;
95 static struct yaffsfs_DirSearchContxt yaffsfs_dsc
[YAFFSFS_N_DSC
];
96 static struct yaffsfs_Inode yaffsfs_inode
[YAFFSFS_N_HANDLES
];
97 static struct yaffsfs_FileDes yaffsfs_fd
[YAFFSFS_N_HANDLES
];
98 static struct yaffsfs_Handle yaffsfs_handle
[YAFFSFS_N_HANDLES
];
100 static int yaffsfs_handlesInitialised
;
102 unsigned yaffs_set_trace(unsigned tm
)
104 yaffs_trace_mask
= tm
;
105 return yaffs_trace_mask
;
108 unsigned yaffs_get_trace(void)
110 return yaffs_trace_mask
;
115 * Inilitalise handle management on start-up.
118 static void yaffsfs_InitHandles(void)
121 if (yaffsfs_handlesInitialised
)
124 memset(yaffsfs_inode
, 0, sizeof(yaffsfs_inode
));
125 memset(yaffsfs_fd
, 0, sizeof(yaffsfs_fd
));
126 memset(yaffsfs_handle
, 0, sizeof(yaffsfs_handle
));
127 memset(yaffsfs_dsc
, 0, sizeof(yaffsfs_dsc
));
129 for (i
= 0; i
< YAFFSFS_N_HANDLES
; i
++)
130 yaffsfs_fd
[i
].inodeId
= -1;
131 for (i
= 0; i
< YAFFSFS_N_HANDLES
; i
++)
132 yaffsfs_handle
[i
].fdId
= -1;
135 static struct yaffsfs_Handle
*yaffsfs_HandleToPointer(int h
)
137 if (h
>= 0 && h
< YAFFSFS_N_HANDLES
)
138 return &yaffsfs_handle
[h
];
142 static struct yaffsfs_FileDes
*yaffsfs_HandleToFileDes(int handle
)
144 struct yaffsfs_Handle
*h
= yaffsfs_HandleToPointer(handle
);
146 if (h
&& h
->useCount
> 0 && h
->fdId
>= 0 && h
->fdId
< YAFFSFS_N_HANDLES
)
147 return &yaffsfs_fd
[h
->fdId
];
152 static struct yaffsfs_Inode
*yaffsfs_HandleToInode(int handle
)
154 struct yaffsfs_FileDes
*fd
= yaffsfs_HandleToFileDes(handle
);
156 if (fd
&& fd
->handleCount
> 0 &&
157 fd
->inodeId
>= 0 && fd
->inodeId
< YAFFSFS_N_HANDLES
)
158 return &yaffsfs_inode
[fd
->inodeId
];
163 static struct yaffs_obj
*yaffsfs_HandleToObject(int handle
)
165 struct yaffsfs_Inode
*in
= yaffsfs_HandleToInode(handle
);
174 * yaffsfs_FindInodeIdForObject
175 * Find the inode entry for an object, if it exists.
178 static int yaffsfs_FindInodeIdForObject(struct yaffs_obj
*obj
)
184 obj
= yaffs_get_equivalent_obj(obj
);
186 /* Look for it in open inode table */
187 for (i
= 0; i
< YAFFSFS_N_HANDLES
&& ret
< 0; i
++) {
188 if (yaffsfs_inode
[i
].iObj
== obj
)
195 * yaffsfs_GetInodeIdForObject
196 * Grab an inode entry when opening a new inode.
198 static int yaffsfs_GetInodeIdForObject(struct yaffs_obj
*obj
)
202 struct yaffsfs_Inode
*in
= NULL
;
205 obj
= yaffs_get_equivalent_obj(obj
);
207 ret
= yaffsfs_FindInodeIdForObject(obj
);
209 for (i
= 0; i
< YAFFSFS_N_HANDLES
&& ret
< 0; i
++) {
210 if (!yaffsfs_inode
[i
].iObj
)
215 in
= &yaffsfs_inode
[ret
];
225 static int yaffsfs_CountHandles(struct yaffs_obj
*obj
)
227 int i
= yaffsfs_FindInodeIdForObject(obj
);
230 return yaffsfs_inode
[i
].count
;
235 static void yaffsfs_ReleaseInode(struct yaffsfs_Inode
*in
)
237 struct yaffs_obj
*obj
;
244 obj
->my_inode
= NULL
;
249 static void yaffsfs_PutInode(int inodeId
)
251 if (inodeId
>= 0 && inodeId
< YAFFSFS_N_HANDLES
) {
252 struct yaffsfs_Inode
*in
= &yaffsfs_inode
[inodeId
];
254 if (in
->count
<= 0) {
255 yaffsfs_ReleaseInode(in
);
261 static int yaffsfs_NewHandle(struct yaffsfs_Handle
**hptr
)
264 struct yaffsfs_Handle
*h
;
266 for (i
= 0; i
< YAFFSFS_N_HANDLES
; i
++) {
267 h
= &yaffsfs_handle
[i
];
268 if (h
->useCount
< 1) {
269 memset(h
, 0, sizeof(struct yaffsfs_Handle
));
280 static int yaffsfs_NewHandleAndFileDes(void)
283 struct yaffsfs_FileDes
*fd
;
284 struct yaffsfs_Handle
*h
= NULL
;
285 int handle
= yaffsfs_NewHandle(&h
);
290 for (i
= 0; i
< YAFFSFS_N_HANDLES
; i
++) {
292 if (fd
->handleCount
< 1) {
293 memset(fd
, 0, sizeof(struct yaffsfs_FileDes
));
301 /* Dump the handle because we could not get a fd */
308 * Increase use of handle when reading/writing a file
309 * Also gets the file descriptor.
312 static int yaffsfs_GetHandle(int handle
)
314 struct yaffsfs_Handle
*h
= yaffsfs_HandleToPointer(handle
);
316 if (h
&& h
->useCount
> 0) {
325 * Let go of a handle when closing a file or aborting an open or
326 * ending a read or write.
329 static int yaffsfs_PutFileDes(int fdId
)
331 struct yaffsfs_FileDes
*fd
;
333 if (fdId
>= 0 && fdId
< YAFFSFS_N_HANDLES
) {
334 fd
= &yaffsfs_fd
[fdId
];
336 if (fd
->handleCount
< 1) {
337 if (fd
->inodeId
>= 0) {
338 yaffsfs_PutInode(fd
->inodeId
);
346 static int yaffsfs_PutHandle(int handle
)
348 struct yaffsfs_Handle
*h
= yaffsfs_HandleToPointer(handle
);
350 if (h
&& h
->useCount
> 0) {
352 if (h
->useCount
< 1) {
353 yaffsfs_PutFileDes(h
->fdId
);
361 static void yaffsfs_BreakDeviceHandles(struct yaffs_dev
*dev
)
363 struct yaffsfs_FileDes
*fd
;
364 struct yaffsfs_Handle
*h
;
365 struct yaffs_obj
*obj
;
367 for (i
= 0; i
< YAFFSFS_N_HANDLES
; i
++) {
368 h
= yaffsfs_HandleToPointer(i
);
369 fd
= yaffsfs_HandleToFileDes(i
);
370 obj
= yaffsfs_HandleToObject(i
);
371 if (h
&& h
->useCount
> 0) {
375 if (fd
&& fd
->handleCount
> 0 && obj
&& obj
->my_dev
== dev
) {
377 yaffsfs_PutInode(fd
->inodeId
);
384 * Stuff to handle names.
386 #ifdef CONFIG_YAFFS_CASE_INSENSITIVE
388 static int yaffs_toupper(YCHAR a
)
390 if (a
>= 'a' && a
<= 'z')
391 return (a
- 'a') + 'A';
396 int yaffsfs_Match(YCHAR a
, YCHAR b
)
398 return (yaffs_toupper(a
) == yaffs_toupper(b
));
401 int yaffsfs_Match(YCHAR a
, YCHAR b
)
408 int yaffsfs_IsPathDivider(YCHAR ch
)
410 const YCHAR
*str
= YAFFS_PATH_DIVIDERS
;
421 int yaffsfs_CheckNameLength(const char *name
)
425 int nameLength
= yaffs_strnlen(name
, YAFFS_MAX_NAME_LENGTH
+ 1);
427 if (nameLength
== 0) {
428 yaffsfs_SetError(-ENOENT
);
430 } else if (nameLength
> YAFFS_MAX_NAME_LENGTH
) {
431 yaffsfs_SetError(-ENAMETOOLONG
);
438 static int yaffsfs_alt_dir_path(const YCHAR
*path
, YCHAR
**ret_path
)
440 YCHAR
*alt_path
= NULL
;
445 * We don't have a definition for max path length.
446 * We will use 3 * max name length instead.
449 path_length
= yaffs_strnlen(path
, (YAFFS_MAX_NAME_LENGTH
+ 1) * 3 + 1);
451 /* If the last character is a path divider, then we need to
452 * trim it back so that the name look-up works properly.
453 * eg. /foo/new_dir/ -> /foo/newdir
454 * Curveball: Need to handle multiple path dividers:
455 * eg. /foof/sdfse///// -> /foo/sdfse
457 if (path_length
> 0 && yaffsfs_IsPathDivider(path
[path_length
- 1])) {
458 alt_path
= kmalloc(path_length
+ 1, 0);
461 yaffs_strcpy(alt_path
, path
);
462 for (i
= path_length
- 1;
463 i
>= 0 && yaffsfs_IsPathDivider(alt_path
[i
]); i
--)
464 alt_path
[i
] = (YCHAR
) 0;
466 *ret_path
= alt_path
;
470 LIST_HEAD(yaffsfs_deviceList
);
475 * Scan the configuration list to find the device
476 * Curveballs: Should match paths that end in '/' too
477 * Curveball2 Might have "/x/ and "/x/y". Need to return the longest match
479 static struct yaffs_dev
*yaffsfs_FindDevice(const YCHAR
*path
,
482 struct list_head
*cfg
;
483 const YCHAR
*leftOver
;
485 struct yaffs_dev
*retval
= NULL
;
486 struct yaffs_dev
*dev
= NULL
;
488 int longestMatch
= -1;
492 * Check all configs, choose the one that:
493 * 1) Actually matches a prefix (ie /a amd /abc will not match
494 * 2) Matches the longest.
496 list_for_each(cfg
, &yaffsfs_deviceList
) {
497 dev
= list_entry(cfg
, struct yaffs_dev
, dev_list
);
503 while (matching
&& *p
&& *leftOver
) {
504 /* Skip over any /s */
505 while (yaffsfs_IsPathDivider(*p
))
508 /* Skip over any /s */
509 while (yaffsfs_IsPathDivider(*leftOver
))
512 /* Now match the text part */
514 *p
&& !yaffsfs_IsPathDivider(*p
) &&
515 *leftOver
&& !yaffsfs_IsPathDivider(*leftOver
)) {
516 if (yaffsfs_Match(*p
, *leftOver
)) {
526 /* Skip over any /s in leftOver */
527 while (yaffsfs_IsPathDivider(*leftOver
))
530 /*Skip over any /s in p */
531 while (yaffsfs_IsPathDivider(*p
))
534 /* p should now be at the end of the string if fully matched */
538 if (matching
&& (thisMatchLength
> longestMatch
)) {
540 *restOfPath
= (YCHAR
*) leftOver
;
542 longestMatch
= thisMatchLength
;
549 static int yaffsfs_CheckPath(const YCHAR
*path
)
554 while (*path
&& n
< YAFFS_MAX_NAME_LENGTH
&& divs
< 100) {
555 if (yaffsfs_IsPathDivider(*path
)) {
563 return (*path
) ? -1 : 0;
566 /* FindMountPoint only returns a dev entry if the path is a mount point */
567 static struct yaffs_dev
*yaffsfs_FindMountPoint(const YCHAR
*path
)
569 struct yaffs_dev
*dev
;
570 YCHAR
*restOfPath
= NULL
;
572 dev
= yaffsfs_FindDevice(path
, &restOfPath
);
573 if (dev
&& restOfPath
&& *restOfPath
)
578 static struct yaffs_obj
*yaffsfs_FindRoot(const YCHAR
*path
,
581 struct yaffs_dev
*dev
;
583 dev
= yaffsfs_FindDevice(path
, restOfPath
);
584 if (dev
&& dev
->is_mounted
)
585 return dev
->root_dir
;
590 static struct yaffs_obj
*yaffsfs_FollowLink(struct yaffs_obj
*obj
,
591 int symDepth
, int *loop
)
595 obj
= yaffs_get_equivalent_obj(obj
);
597 while (obj
&& obj
->variant_type
== YAFFS_OBJECT_TYPE_SYMLINK
) {
598 YCHAR
*alias
= obj
->variant
.symlink_variant
.alias
;
600 if (yaffsfs_IsPathDivider(*alias
))
601 /* Starts with a /, need to scan from root up */
602 obj
= yaffsfs_FindObject(NULL
, alias
, symDepth
++,
603 1, NULL
, NULL
, loop
);
606 * Relative to here so use the parent of the
609 obj
= yaffsfs_FindObject(obj
->parent
, alias
, symDepth
++,
610 1, NULL
, NULL
, loop
);
616 * yaffsfs_FindDirectory
617 * Parse a path to determine the directory and the name within the directory.
619 * eg. "/data/xx/ff" --> puts name="ff" and returns the directory "/data/xx"
621 static struct yaffs_obj
*yaffsfs_DoFindDirectory(struct yaffs_obj
*startDir
,
623 YCHAR
**name
, int symDepth
,
624 int *notDir
, int *loop
)
626 struct yaffs_obj
*dir
;
628 YCHAR str
[YAFFS_MAX_NAME_LENGTH
+ 1];
631 if (symDepth
> YAFFSFS_MAX_SYMLINK_DEREFERENCES
) {
639 restOfPath
= (YCHAR
*) path
;
641 dir
= yaffsfs_FindRoot(path
, &restOfPath
);
646 * curve ball: also throw away surplus '/'
647 * eg. "/ram/x////ff" gets treated the same as "/ram/x/ff"
649 while (yaffsfs_IsPathDivider(*restOfPath
))
650 restOfPath
++; /* get rid of '/' */
655 while (*restOfPath
&& !yaffsfs_IsPathDivider(*restOfPath
)) {
656 if (i
< YAFFS_MAX_NAME_LENGTH
) {
657 str
[i
] = *restOfPath
;
665 /* got to the end of the string */
668 if (yaffs_strcmp(str
, _Y(".")) == 0) {
670 } else if (yaffs_strcmp(str
, _Y("..")) == 0) {
673 dir
= yaffs_find_by_name(dir
, str
);
675 dir
= yaffsfs_FollowLink(dir
, symDepth
, loop
);
677 if (dir
&& dir
->variant_type
!=
678 YAFFS_OBJECT_TYPE_DIRECTORY
) {
687 /* directory did not exist. */
691 static struct yaffs_obj
*yaffsfs_FindDirectory(struct yaffs_obj
*relDir
,
695 int *notDir
, int *loop
)
697 return yaffsfs_DoFindDirectory(relDir
, path
, name
, symDepth
, notDir
,
702 * yaffsfs_FindObject turns a path for an existing object into the object
704 static struct yaffs_obj
*yaffsfs_FindObject(struct yaffs_obj
*relDir
,
705 const YCHAR
*path
, int symDepth
,
707 struct yaffs_obj
**dirOut
,
708 int *notDir
, int *loop
)
710 struct yaffs_obj
*dir
;
711 struct yaffs_obj
*obj
;
715 yaffsfs_FindDirectory(relDir
, path
, &name
, symDepth
, notDir
, loop
);
721 obj
= yaffs_find_by_name(dir
, name
);
726 obj
= yaffs_get_equivalent_obj(obj
);
731 /*************************************************************************
732 * Start of yaffsfs visible functions.
733 *************************************************************************/
735 int yaffs_dup(int handle
)
737 int newHandleNumber
= -1;
738 struct yaffsfs_FileDes
*existingFD
= NULL
;
739 struct yaffsfs_Handle
*existingHandle
= NULL
;
740 struct yaffsfs_Handle
*newHandle
= NULL
;
743 existingHandle
= yaffsfs_HandleToPointer(handle
);
744 existingFD
= yaffsfs_HandleToFileDes(handle
);
746 newHandleNumber
= yaffsfs_NewHandle(&newHandle
);
748 newHandle
->fdId
= existingHandle
->fdId
;
749 existingFD
->handleCount
++;
755 yaffsfs_SetError(-EBADF
);
757 yaffsfs_SetError(-ENOMEM
);
759 return newHandleNumber
;
763 static int yaffsfs_TooManyObjects(struct yaffs_dev
*dev
)
765 int current_objects
= dev
->n_obj
- dev
->n_deleted_files
;
767 if (dev
->param
.max_objects
&& current_objects
> dev
->param
.max_objects
)
773 int yaffs_open_sharing(const YCHAR
*path
, int oflag
, int mode
, int sharing
)
775 struct yaffs_obj
*obj
= NULL
;
776 struct yaffs_obj
*dir
= NULL
;
779 struct yaffsfs_FileDes
*fd
= NULL
;
782 int errorReported
= 0;
783 int rwflags
= oflag
& (O_RDWR
| O_RDONLY
| O_WRONLY
);
784 u8 shareRead
= (sharing
& YAFFS_SHARE_READ
) ? 1 : 0;
785 u8 shareWrite
= (sharing
& YAFFS_SHARE_WRITE
) ? 1 : 0;
786 u8 sharedReadAllowed
;
787 u8 sharedWriteAllowed
;
796 yaffsfs_SetError(-EFAULT
);
800 if (yaffsfs_CheckPath(path
) < 0) {
801 yaffsfs_SetError(-ENAMETOOLONG
);
805 /* O_EXCL only has meaning if O_CREAT is specified */
806 if (!(oflag
& O_CREAT
))
809 /* O_TRUNC has no meaning if (O_CREAT | O_EXCL) is specified */
810 if ((oflag
& O_CREAT
) & (oflag
& O_EXCL
))
813 /* Todo: Are there any more flag combos to sanitise ? */
815 /* Figure out if reading or writing is requested */
817 readRequested
= (rwflags
== O_RDWR
|| rwflags
== O_RDONLY
) ? 1 : 0;
818 writeRequested
= (rwflags
== O_RDWR
|| rwflags
== O_WRONLY
) ? 1 : 0;
822 handle
= yaffsfs_NewHandleAndFileDes();
825 yaffsfs_SetError(-ENFILE
);
829 fd
= yaffsfs_HandleToFileDes(handle
);
831 /* try to find the exisiting object */
832 obj
= yaffsfs_FindObject(NULL
, path
, 0, 1, NULL
, NULL
, NULL
);
834 obj
= yaffsfs_FollowLink(obj
, symDepth
++, &loop
);
837 obj
->variant_type
!= YAFFS_OBJECT_TYPE_FILE
&&
838 obj
->variant_type
!= YAFFS_OBJECT_TYPE_DIRECTORY
)
843 /* The file already exists or it might be a directory */
845 /* A directory can't be opened as a file */
846 if (obj
->variant_type
== YAFFS_OBJECT_TYPE_DIRECTORY
) {
848 yaffsfs_SetError(-EISDIR
);
852 /* Open should fail if O_CREAT and O_EXCL are specified
853 * for a file that exists.
855 if (!errorReported
&&
856 (oflag
& O_EXCL
) && (oflag
& O_CREAT
)) {
858 yaffsfs_SetError(-EEXIST
);
862 /* Check file permissions */
863 if (readRequested
&& !(obj
->yst_mode
& S_IREAD
))
866 if (writeRequested
&& !(obj
->yst_mode
& S_IWRITE
))
869 if (!errorReported
&& writeRequested
&&
870 obj
->my_dev
->read_only
) {
872 yaffsfs_SetError(-EROFS
);
876 if (openDenied
&& !errorReported
) {
877 yaffsfs_SetError(-EACCES
);
881 /* Check sharing of an existing object. */
883 struct yaffsfs_FileDes
*fdx
;
886 sharedReadAllowed
= 1;
887 sharedWriteAllowed
= 1;
890 for (i
= 0; i
< YAFFSFS_N_HANDLES
; i
++) {
891 fdx
= &yaffsfs_fd
[i
];
892 if (fdx
->handleCount
> 0 &&
894 yaffsfs_inode
[fdx
->inodeId
].iObj
897 sharedReadAllowed
= 0;
898 if (!fdx
->shareWrite
)
899 sharedWriteAllowed
= 0;
907 if ((!sharedReadAllowed
&& readRequested
) ||
908 (!shareRead
&& alreadyReading
) ||
909 (!sharedWriteAllowed
&& writeRequested
) ||
910 (!shareWrite
&& alreadyWriting
)) {
912 yaffsfs_SetError(-EBUSY
);
919 /* If we could not open an existing object, then let's see if
920 * the directory exists. If not, error.
922 if (!obj
&& !errorReported
) {
923 dir
= yaffsfs_FindDirectory(NULL
, path
, &name
, 0,
925 if (!dir
&& notDir
) {
926 yaffsfs_SetError(-ENOTDIR
);
929 yaffsfs_SetError(-ELOOP
);
932 yaffsfs_SetError(-ENOENT
);
937 if (!obj
&& dir
&& !errorReported
&& (oflag
& O_CREAT
)) {
938 /* Let's see if we can create this file */
939 if (dir
->my_dev
->read_only
) {
940 yaffsfs_SetError(-EROFS
);
942 } else if (yaffsfs_TooManyObjects(dir
->my_dev
)) {
943 yaffsfs_SetError(-ENFILE
);
946 obj
= yaffs_create_file(dir
, name
, mode
, 0, 0);
948 if (!obj
&& !errorReported
) {
949 yaffsfs_SetError(-ENOSPC
);
954 if (!obj
&& dir
&& !errorReported
&& !(oflag
& O_CREAT
)) {
955 yaffsfs_SetError(-ENOENT
);
959 if (obj
&& !openDenied
) {
960 int inodeId
= yaffsfs_GetInodeIdForObject(obj
);
964 * Todo: Fix any problem if inodes run out,
965 * That can't happen if the number of inode
966 * items >= number of handles.
970 fd
->inodeId
= inodeId
;
971 fd
->reading
= readRequested
;
972 fd
->writing
= writeRequested
;
973 fd
->append
= (oflag
& O_APPEND
) ? 1 : 0;
975 fd
->shareRead
= shareRead
;
976 fd
->shareWrite
= shareWrite
;
978 /* Hook inode to object */
979 obj
->my_inode
= (void *)&yaffsfs_inode
[inodeId
];
981 if ((oflag
& O_TRUNC
) && fd
->writing
)
982 yaffs_resize_file(obj
, 0);
984 yaffsfs_PutHandle(handle
);
986 yaffsfs_SetError(0); /* Problem */
996 int yaffs_open(const YCHAR
*path
, int oflag
, int mode
)
998 return yaffs_open_sharing(path
, oflag
, mode
,
999 YAFFS_SHARE_READ
| YAFFS_SHARE_WRITE
);
1002 int yaffs_Dofsync(int handle
, int datasync
)
1005 struct yaffs_obj
*obj
;
1009 obj
= yaffsfs_HandleToObject(handle
);
1012 yaffsfs_SetError(-EBADF
);
1013 else if (obj
->my_dev
->read_only
)
1014 yaffsfs_SetError(-EROFS
);
1016 yaffs_flush_file(obj
, 1, datasync
);
1025 int yaffs_fsync(int handle
)
1027 return yaffs_Dofsync(handle
, 0);
1030 int yaffs_flush(int handle
)
1032 return yaffs_fsync(handle
);
1035 int yaffs_fdatasync(int handle
)
1037 return yaffs_Dofsync(handle
, 1);
1040 int yaffs_close(int handle
)
1042 struct yaffsfs_Handle
*h
= NULL
;
1043 struct yaffs_obj
*obj
= NULL
;
1048 h
= yaffsfs_HandleToPointer(handle
);
1049 obj
= yaffsfs_HandleToObject(handle
);
1052 yaffsfs_SetError(-EBADF
);
1055 yaffs_flush_file(obj
, 1, 0);
1056 yaffsfs_PutHandle(handle
);
1065 int yaffsfs_do_read(int handle
, void *vbuf
, unsigned int nbyte
,
1066 int isPread
, loff_t offset
)
1068 struct yaffsfs_FileDes
*fd
= NULL
;
1069 struct yaffs_obj
*obj
= NULL
;
1071 loff_t startPos
= 0;
1077 u8
*buf
= (u8
*) vbuf
;
1080 yaffsfs_SetError(-EFAULT
);
1085 fd
= yaffsfs_HandleToFileDes(handle
);
1086 obj
= yaffsfs_HandleToObject(handle
);
1090 yaffsfs_SetError(-EBADF
);
1092 } else if (!fd
->reading
) {
1093 /* Not a reading handle */
1094 yaffsfs_SetError(-EINVAL
);
1096 } else if (nbyte
> YAFFS_MAX_FILE_SIZE
) {
1097 yaffsfs_SetError(-EINVAL
);
1103 startPos
= fd
->position
;
1107 if (yaffs_get_obj_length(obj
) > pos
)
1108 maxRead
= yaffs_get_obj_length(obj
) - pos
;
1112 if (nbyte
> maxRead
)
1115 yaffsfs_GetHandle(handle
);
1117 endPos
= pos
+ nbyte
;
1119 if (pos
< 0 || pos
> YAFFS_MAX_FILE_SIZE
||
1120 nbyte
> YAFFS_MAX_FILE_SIZE
||
1121 endPos
< 0 || endPos
> YAFFS_MAX_FILE_SIZE
) {
1127 nToRead
= YAFFSFS_RW_SIZE
-
1128 (pos
& (YAFFSFS_RW_SIZE
- 1));
1129 if (nToRead
> nbyte
)
1133 * Need to reverify object in case the device was
1134 * unmounted in another thread.
1136 obj
= yaffsfs_HandleToObject(handle
);
1140 nRead
= yaffs_file_rd(obj
, buf
, pos
, nToRead
);
1148 if (nRead
== nToRead
)
1151 nbyte
= 0; /* no more to read */
1160 yaffsfs_PutHandle(handle
);
1164 fd
->position
= startPos
+ totalRead
;
1166 yaffsfs_SetError(-EINVAL
);
1173 return (totalRead
>= 0) ? totalRead
: -1;
1177 int yaffs_read(int handle
, void *buf
, unsigned int nbyte
)
1179 return yaffsfs_do_read(handle
, buf
, nbyte
, 0, 0);
1182 int yaffs_pread(int handle
, void *buf
, unsigned int nbyte
, loff_t offset
)
1184 return yaffsfs_do_read(handle
, buf
, nbyte
, 1, offset
);
1187 int yaffsfs_do_write(int handle
, const void *vbuf
, unsigned int nbyte
,
1188 int isPwrite
, loff_t offset
)
1190 struct yaffsfs_FileDes
*fd
= NULL
;
1191 struct yaffs_obj
*obj
= NULL
;
1193 loff_t startPos
= 0;
1196 int totalWritten
= 0;
1197 int write_trhrough
= 0;
1199 const u8
*buf
= (const u8
*)vbuf
;
1202 yaffsfs_SetError(-EFAULT
);
1207 fd
= yaffsfs_HandleToFileDes(handle
);
1208 obj
= yaffsfs_HandleToObject(handle
);
1212 yaffsfs_SetError(-EBADF
);
1214 } else if (!fd
->writing
) {
1215 yaffsfs_SetError(-EINVAL
);
1217 } else if (obj
->my_dev
->read_only
) {
1218 yaffsfs_SetError(-EROFS
);
1222 startPos
= yaffs_get_obj_length(obj
);
1226 startPos
= fd
->position
;
1228 yaffsfs_GetHandle(handle
);
1230 endPos
= pos
+ nbyte
;
1232 if (pos
< 0 || pos
> YAFFS_MAX_FILE_SIZE
||
1233 nbyte
> YAFFS_MAX_FILE_SIZE
||
1234 endPos
< 0 || endPos
> YAFFS_MAX_FILE_SIZE
) {
1241 nToWrite
= YAFFSFS_RW_SIZE
-
1242 (pos
& (YAFFSFS_RW_SIZE
- 1));
1243 if (nToWrite
> nbyte
)
1247 * Need to reverify object in case the device was
1248 * remounted or unmounted in another thread.
1250 obj
= yaffsfs_HandleToObject(handle
);
1251 if (!obj
|| obj
->my_dev
->read_only
)
1255 yaffs_wr_file(obj
, buf
, pos
, nToWrite
,
1258 totalWritten
+= nWritten
;
1263 if (nWritten
== nToWrite
)
1268 if (nWritten
< 1 && totalWritten
< 1) {
1269 yaffsfs_SetError(-ENOSPC
);
1279 yaffsfs_PutHandle(handle
);
1282 if (totalWritten
> 0)
1283 fd
->position
= startPos
+ totalWritten
;
1285 yaffsfs_SetError(-EINVAL
);
1291 return (totalWritten
>= 0) ? totalWritten
: -1;
1294 int yaffs_write(int fd
, const void *buf
, unsigned int nbyte
)
1296 return yaffsfs_do_write(fd
, buf
, nbyte
, 0, 0);
1299 int yaffs_pwrite(int fd
, const void *buf
, unsigned int nbyte
, loff_t offset
)
1301 return yaffsfs_do_write(fd
, buf
, nbyte
, 1, offset
);
1304 int yaffs_truncate(const YCHAR
*path
, loff_t new_size
)
1306 struct yaffs_obj
*obj
= NULL
;
1307 struct yaffs_obj
*dir
= NULL
;
1308 int result
= YAFFS_FAIL
;
1313 yaffsfs_SetError(-EFAULT
);
1317 if (yaffsfs_CheckPath(path
) < 0) {
1318 yaffsfs_SetError(-ENAMETOOLONG
);
1324 obj
= yaffsfs_FindObject(NULL
, path
, 0, 1, &dir
, ¬Dir
, &loop
);
1325 obj
= yaffsfs_FollowLink(obj
, 0, &loop
);
1328 yaffsfs_SetError(-ENOTDIR
);
1330 yaffsfs_SetError(-ELOOP
);
1331 else if (!dir
|| !obj
)
1332 yaffsfs_SetError(-ENOENT
);
1333 else if (obj
->my_dev
->read_only
)
1334 yaffsfs_SetError(-EROFS
);
1335 else if (obj
->variant_type
!= YAFFS_OBJECT_TYPE_FILE
)
1336 yaffsfs_SetError(-EISDIR
);
1337 else if (obj
->my_dev
->read_only
)
1338 yaffsfs_SetError(-EROFS
);
1339 else if (new_size
< 0 || new_size
> YAFFS_MAX_FILE_SIZE
)
1340 yaffsfs_SetError(-EINVAL
);
1342 result
= yaffs_resize_file(obj
, new_size
);
1346 return (result
) ? 0 : -1;
1349 int yaffs_ftruncate(int handle
, loff_t new_size
)
1351 struct yaffsfs_FileDes
*fd
= NULL
;
1352 struct yaffs_obj
*obj
= NULL
;
1356 fd
= yaffsfs_HandleToFileDes(handle
);
1357 obj
= yaffsfs_HandleToObject(handle
);
1361 yaffsfs_SetError(-EBADF
);
1362 else if (!fd
->writing
)
1363 yaffsfs_SetError(-EINVAL
);
1364 else if (obj
->my_dev
->read_only
)
1365 yaffsfs_SetError(-EROFS
);
1366 else if (new_size
< 0 || new_size
> YAFFS_MAX_FILE_SIZE
)
1367 yaffsfs_SetError(-EINVAL
);
1369 /* resize the file */
1370 result
= yaffs_resize_file(obj
, new_size
);
1373 return (result
) ? 0 : -1;
1377 loff_t
yaffs_lseek(int handle
, loff_t offset
, int whence
)
1379 struct yaffsfs_FileDes
*fd
= NULL
;
1380 struct yaffs_obj
*obj
= NULL
;
1385 fd
= yaffsfs_HandleToFileDes(handle
);
1386 obj
= yaffsfs_HandleToObject(handle
);
1389 yaffsfs_SetError(-EBADF
);
1390 else if (offset
> YAFFS_MAX_FILE_SIZE
)
1391 yaffsfs_SetError(-EINVAL
);
1393 if (whence
== SEEK_SET
) {
1396 } else if (whence
== SEEK_CUR
) {
1397 if ((fd
->position
+ offset
) >= 0)
1398 pos
= (fd
->position
+ offset
);
1399 } else if (whence
== SEEK_END
) {
1400 fSize
= yaffs_get_obj_length(obj
);
1401 if (fSize
>= 0 && (fSize
+ offset
) >= 0)
1402 pos
= fSize
+ offset
;
1405 if (pos
>= 0 && pos
<= YAFFS_MAX_FILE_SIZE
)
1408 yaffsfs_SetError(-EINVAL
);
1418 int yaffsfs_DoUnlink(const YCHAR
*path
, int isDirectory
)
1420 struct yaffs_obj
*dir
= NULL
;
1421 struct yaffs_obj
*obj
= NULL
;
1423 int result
= YAFFS_FAIL
;
1428 yaffsfs_SetError(-EFAULT
);
1432 if (yaffsfs_CheckPath(path
) < 0) {
1433 yaffsfs_SetError(-ENAMETOOLONG
);
1439 obj
= yaffsfs_FindObject(NULL
, path
, 0, 0, NULL
, NULL
, NULL
);
1440 dir
= yaffsfs_FindDirectory(NULL
, path
, &name
, 0, ¬Dir
, &loop
);
1443 yaffsfs_SetError(-ENOTDIR
);
1445 yaffsfs_SetError(-ELOOP
);
1447 yaffsfs_SetError(-ENOENT
);
1448 else if (yaffs_strncmp(name
, _Y("."), 2) == 0)
1449 yaffsfs_SetError(-EINVAL
);
1451 yaffsfs_SetError(-ENOENT
);
1452 else if (obj
->my_dev
->read_only
)
1453 yaffsfs_SetError(-EROFS
);
1454 else if (!isDirectory
&&
1455 obj
->variant_type
== YAFFS_OBJECT_TYPE_DIRECTORY
)
1456 yaffsfs_SetError(-EISDIR
);
1457 else if (isDirectory
&&
1458 obj
->variant_type
!= YAFFS_OBJECT_TYPE_DIRECTORY
)
1459 yaffsfs_SetError(-ENOTDIR
);
1460 else if (isDirectory
&& obj
== obj
->my_dev
->root_dir
)
1461 yaffsfs_SetError(-EBUSY
); /* Can't rmdir a root */
1463 result
= yaffs_unlinker(dir
, name
);
1465 if (result
== YAFFS_FAIL
&& isDirectory
)
1466 yaffsfs_SetError(-ENOTEMPTY
);
1471 return (result
== YAFFS_FAIL
) ? -1 : 0;
1474 int yaffs_unlink(const YCHAR
*path
)
1476 return yaffsfs_DoUnlink(path
, 0);
1479 int yaffs_rename(const YCHAR
*oldPath
, const YCHAR
*newPath
)
1481 struct yaffs_obj
*olddir
= NULL
;
1482 struct yaffs_obj
*newdir
= NULL
;
1483 struct yaffs_obj
*obj
= NULL
;
1484 struct yaffs_obj
*newobj
= NULL
;
1487 int result
= YAFFS_FAIL
;
1488 int rename_allowed
= 1;
1494 YCHAR
*alt_newpath
= NULL
;
1496 if (!oldPath
|| !newPath
) {
1497 yaffsfs_SetError(-EFAULT
);
1501 if (yaffsfs_CheckPath(oldPath
) < 0 || yaffsfs_CheckPath(newPath
) < 0) {
1502 yaffsfs_SetError(-ENAMETOOLONG
);
1506 if (yaffsfs_alt_dir_path(newPath
, &alt_newpath
) < 0) {
1507 yaffsfs_SetError(-ENOMEM
);
1511 newPath
= alt_newpath
;
1515 olddir
= yaffsfs_FindDirectory(NULL
, oldPath
, &oldname
, 0,
1516 ¬OldDir
, &oldLoop
);
1517 newdir
= yaffsfs_FindDirectory(NULL
, newPath
, &newname
, 0,
1518 ¬NewDir
, &newLoop
);
1519 obj
= yaffsfs_FindObject(NULL
, oldPath
, 0, 0, NULL
, NULL
, NULL
);
1520 newobj
= yaffsfs_FindObject(NULL
, newPath
, 0, 0, NULL
, NULL
, NULL
);
1522 /* If the object being renamed is a directory and the
1523 * path ended with a "/" then the olddir == obj.
1524 * We pass through NULL for the old name to tell the lower layers
1525 * to use olddir as the object.
1531 if ((!olddir
&& notOldDir
) || (!newdir
&& notNewDir
)) {
1532 yaffsfs_SetError(-ENOTDIR
);
1534 } else if (oldLoop
|| newLoop
) {
1535 yaffsfs_SetError(-ELOOP
);
1537 } else if (olddir
&& oldname
&&
1538 yaffs_strncmp(oldname
, _Y("."), 2) == 0) {
1539 yaffsfs_SetError(-EINVAL
);
1541 } else if (!olddir
|| !newdir
|| !obj
) {
1542 yaffsfs_SetError(-ENOENT
);
1544 } else if (obj
->my_dev
->read_only
) {
1545 yaffsfs_SetError(-EROFS
);
1547 } else if (yaffs_is_non_empty_dir(newobj
)) {
1548 yaffsfs_SetError(-ENOTEMPTY
);
1550 } else if (olddir
->my_dev
!= newdir
->my_dev
) {
1551 /* Rename must be on same device */
1552 yaffsfs_SetError(-EXDEV
);
1554 } else if (obj
&& obj
->variant_type
== YAFFS_OBJECT_TYPE_DIRECTORY
) {
1556 * It is a directory, check that it is not being renamed to
1557 * being its own decendent.
1558 * Do this by tracing from the new directory back to the root,
1562 struct yaffs_obj
*xx
= newdir
;
1564 while (rename_allowed
&& xx
) {
1569 if (!rename_allowed
)
1570 yaffsfs_SetError(-EINVAL
);
1574 result
= yaffs_rename_obj(olddir
, oldname
, newdir
, newname
);
1580 return (result
== YAFFS_FAIL
) ? -1 : 0;
1583 static int yaffsfs_DoStat(struct yaffs_obj
*obj
, struct yaffs_stat
*buf
)
1587 obj
= yaffs_get_equivalent_obj(obj
);
1590 buf
->st_dev
= (int)obj
->my_dev
->os_context
;
1591 buf
->st_ino
= obj
->obj_id
;
1592 buf
->st_mode
= obj
->yst_mode
& ~S_IFMT
;
1594 if (obj
->variant_type
== YAFFS_OBJECT_TYPE_DIRECTORY
)
1595 buf
->st_mode
|= S_IFDIR
;
1596 else if (obj
->variant_type
== YAFFS_OBJECT_TYPE_SYMLINK
)
1597 buf
->st_mode
|= S_IFLNK
;
1598 else if (obj
->variant_type
== YAFFS_OBJECT_TYPE_FILE
)
1599 buf
->st_mode
|= S_IFREG
;
1601 buf
->st_nlink
= yaffs_get_obj_link_count(obj
);
1604 buf
->st_rdev
= obj
->yst_rdev
;
1605 buf
->st_size
= yaffs_get_obj_length(obj
);
1606 buf
->st_blksize
= obj
->my_dev
->data_bytes_per_chunk
;
1607 buf
->st_blocks
= lldiv(buf
->st_size
+ buf
->st_blksize
- 1,
1609 #if CONFIG_YAFFS_WINCE
1610 buf
->yst_wince_atime
[0] = obj
->win_atime
[0];
1611 buf
->yst_wince_atime
[1] = obj
->win_atime
[1];
1612 buf
->yst_wince_ctime
[0] = obj
->win_ctime
[0];
1613 buf
->yst_wince_ctime
[1] = obj
->win_ctime
[1];
1614 buf
->yst_wince_mtime
[0] = obj
->win_mtime
[0];
1615 buf
->yst_wince_mtime
[1] = obj
->win_mtime
[1];
1617 buf
->yst_atime
= obj
->yst_atime
;
1618 buf
->yst_ctime
= obj
->yst_ctime
;
1619 buf
->yst_mtime
= obj
->yst_mtime
;
1626 static int yaffsfs_DoStatOrLStat(const YCHAR
*path
,
1627 struct yaffs_stat
*buf
, int doLStat
)
1629 struct yaffs_obj
*obj
= NULL
;
1630 struct yaffs_obj
*dir
= NULL
;
1635 if (!path
|| !buf
) {
1636 yaffsfs_SetError(-EFAULT
);
1640 if (yaffsfs_CheckPath(path
) < 0) {
1641 yaffsfs_SetError(-ENAMETOOLONG
);
1647 obj
= yaffsfs_FindObject(NULL
, path
, 0, 1, &dir
, ¬Dir
, &loop
);
1649 if (!doLStat
&& obj
)
1650 obj
= yaffsfs_FollowLink(obj
, 0, &loop
);
1653 yaffsfs_SetError(-ENOTDIR
);
1655 yaffsfs_SetError(-ELOOP
);
1656 else if (!dir
|| !obj
)
1657 yaffsfs_SetError(-ENOENT
);
1659 retVal
= yaffsfs_DoStat(obj
, buf
);
1667 int yaffs_stat(const YCHAR
*path
, struct yaffs_stat
*buf
)
1669 return yaffsfs_DoStatOrLStat(path
, buf
, 0);
1672 int yaffs_lstat(const YCHAR
*path
, struct yaffs_stat
*buf
)
1674 return yaffsfs_DoStatOrLStat(path
, buf
, 1);
1677 int yaffs_fstat(int fd
, struct yaffs_stat
*buf
)
1679 struct yaffs_obj
*obj
;
1684 yaffsfs_SetError(-EFAULT
);
1689 obj
= yaffsfs_HandleToObject(fd
);
1692 retVal
= yaffsfs_DoStat(obj
, buf
);
1695 yaffsfs_SetError(-EBADF
);
1702 static int yaffsfs_DoUtime(struct yaffs_obj
*obj
,
1703 const struct yaffs_utimbuf
*buf
)
1708 struct yaffs_utimbuf local
;
1710 obj
= yaffs_get_equivalent_obj(obj
);
1712 if (obj
&& obj
->my_dev
->read_only
) {
1713 yaffsfs_SetError(-EROFS
);
1718 local
.actime
= Y_CURRENT_TIME
;
1719 local
.modtime
= local
.actime
;
1724 obj
->yst_atime
= buf
->actime
;
1725 obj
->yst_mtime
= buf
->modtime
;
1727 result
= yaffs_flush_file(obj
, 0, 0);
1728 retVal
= result
== YAFFS_OK
? 0 : -1;
1734 int yaffs_utime(const YCHAR
*path
, const struct yaffs_utimbuf
*buf
)
1736 struct yaffs_obj
*obj
= NULL
;
1737 struct yaffs_obj
*dir
= NULL
;
1743 yaffsfs_SetError(-EFAULT
);
1747 if (yaffsfs_CheckPath(path
) < 0) {
1748 yaffsfs_SetError(-ENAMETOOLONG
);
1754 obj
= yaffsfs_FindObject(NULL
, path
, 0, 1, &dir
, ¬Dir
, &loop
);
1757 yaffsfs_SetError(-ENOTDIR
);
1759 yaffsfs_SetError(-ELOOP
);
1760 else if (!dir
|| !obj
)
1761 yaffsfs_SetError(-ENOENT
);
1763 retVal
= yaffsfs_DoUtime(obj
, buf
);
1771 int yaffs_futime(int fd
, const struct yaffs_utimbuf
*buf
)
1773 struct yaffs_obj
*obj
;
1778 obj
= yaffsfs_HandleToObject(fd
);
1781 retVal
= yaffsfs_DoUtime(obj
, buf
);
1784 yaffsfs_SetError(-EBADF
);
1791 #ifndef CONFIG_YAFFS_WINCE
1792 /* xattrib functions */
1794 static int yaffs_do_setxattr(const YCHAR
*path
, const char *name
,
1795 const void *data
, int size
, int flags
, int follow
)
1797 struct yaffs_obj
*obj
;
1798 struct yaffs_obj
*dir
;
1804 if (!path
|| !name
|| !data
) {
1805 yaffsfs_SetError(-EFAULT
);
1809 if (yaffsfs_CheckPath(path
) < 0) {
1810 yaffsfs_SetError(-ENAMETOOLONG
);
1816 obj
= yaffsfs_FindObject(NULL
, path
, 0, 1, &dir
, ¬Dir
, &loop
);
1819 obj
= yaffsfs_FollowLink(obj
, 0, &loop
);
1822 yaffsfs_SetError(-ENOTDIR
);
1824 yaffsfs_SetError(-ELOOP
);
1825 else if (!dir
|| !obj
)
1826 yaffsfs_SetError(-ENOENT
);
1828 retVal
= yaffs_set_xattrib(obj
, name
, data
, size
, flags
);
1830 yaffsfs_SetError(retVal
);
1841 int yaffs_setxattr(const YCHAR
*path
, const char *name
,
1842 const void *data
, int size
, int flags
)
1844 return yaffs_do_setxattr(path
, name
, data
, size
, flags
, 1);
1847 int yaffs_lsetxattr(const YCHAR
*path
, const char *name
,
1848 const void *data
, int size
, int flags
)
1850 return yaffs_do_setxattr(path
, name
, data
, size
, flags
, 0);
1853 int yaffs_fsetxattr(int fd
, const char *name
,
1854 const void *data
, int size
, int flags
)
1856 struct yaffs_obj
*obj
;
1860 if (!name
|| !data
) {
1861 yaffsfs_SetError(-EFAULT
);
1866 obj
= yaffsfs_HandleToObject(fd
);
1869 yaffsfs_SetError(-EBADF
);
1871 retVal
= yaffs_set_xattrib(obj
, name
, data
, size
, flags
);
1873 yaffsfs_SetError(retVal
);
1883 static int yaffs_do_getxattr(const YCHAR
*path
, const char *name
,
1884 void *data
, int size
, int follow
)
1886 struct yaffs_obj
*obj
;
1887 struct yaffs_obj
*dir
;
1892 if (!path
|| !name
|| !data
) {
1893 yaffsfs_SetError(-EFAULT
);
1897 if (yaffsfs_CheckPath(path
) < 0) {
1898 yaffsfs_SetError(-ENAMETOOLONG
);
1904 obj
= yaffsfs_FindObject(NULL
, path
, 0, 1, &dir
, ¬Dir
, &loop
);
1907 obj
= yaffsfs_FollowLink(obj
, 0, &loop
);
1910 yaffsfs_SetError(-ENOTDIR
);
1912 yaffsfs_SetError(-ELOOP
);
1913 else if (!dir
|| !obj
)
1914 yaffsfs_SetError(-ENOENT
);
1916 retVal
= yaffs_get_xattrib(obj
, name
, data
, size
);
1918 yaffsfs_SetError(retVal
);
1928 int yaffs_getxattr(const YCHAR
*path
, const char *name
, void *data
, int size
)
1930 return yaffs_do_getxattr(path
, name
, data
, size
, 1);
1933 int yaffs_lgetxattr(const YCHAR
*path
, const char *name
, void *data
, int size
)
1935 return yaffs_do_getxattr(path
, name
, data
, size
, 0);
1938 int yaffs_fgetxattr(int fd
, const char *name
, void *data
, int size
)
1940 struct yaffs_obj
*obj
;
1944 if (!name
|| !data
) {
1945 yaffsfs_SetError(-EFAULT
);
1950 obj
= yaffsfs_HandleToObject(fd
);
1953 retVal
= yaffs_get_xattrib(obj
, name
, data
, size
);
1955 yaffsfs_SetError(retVal
);
1960 yaffsfs_SetError(-EBADF
);
1967 static int yaffs_do_listxattr(const YCHAR
*path
, char *data
,
1968 int size
, int follow
)
1970 struct yaffs_obj
*obj
= NULL
;
1971 struct yaffs_obj
*dir
= NULL
;
1976 if (!path
|| !data
) {
1977 yaffsfs_SetError(-EFAULT
);
1981 if (yaffsfs_CheckPath(path
) < 0) {
1982 yaffsfs_SetError(-ENAMETOOLONG
);
1988 obj
= yaffsfs_FindObject(NULL
, path
, 0, 1, &dir
, ¬Dir
, &loop
);
1991 obj
= yaffsfs_FollowLink(obj
, 0, &loop
);
1994 yaffsfs_SetError(-ENOTDIR
);
1996 yaffsfs_SetError(-ELOOP
);
1997 else if (!dir
|| !obj
)
1998 yaffsfs_SetError(-ENOENT
);
2000 retVal
= yaffs_list_xattrib(obj
, data
, size
);
2002 yaffsfs_SetError(retVal
);
2013 int yaffs_listxattr(const YCHAR
*path
, char *data
, int size
)
2015 return yaffs_do_listxattr(path
, data
, size
, 1);
2018 int yaffs_llistxattr(const YCHAR
*path
, char *data
, int size
)
2020 return yaffs_do_listxattr(path
, data
, size
, 0);
2023 int yaffs_flistxattr(int fd
, char *data
, int size
)
2025 struct yaffs_obj
*obj
;
2030 yaffsfs_SetError(-EFAULT
);
2035 obj
= yaffsfs_HandleToObject(fd
);
2038 retVal
= yaffs_list_xattrib(obj
, data
, size
);
2040 yaffsfs_SetError(retVal
);
2045 yaffsfs_SetError(-EBADF
);
2052 static int yaffs_do_removexattr(const YCHAR
*path
, const char *name
,
2055 struct yaffs_obj
*obj
= NULL
;
2056 struct yaffs_obj
*dir
= NULL
;
2061 if (!path
|| !name
) {
2062 yaffsfs_SetError(-EFAULT
);
2066 if (yaffsfs_CheckPath(path
) < 0) {
2067 yaffsfs_SetError(-ENAMETOOLONG
);
2073 obj
= yaffsfs_FindObject(NULL
, path
, 0, 1, &dir
, ¬Dir
, &loop
);
2076 obj
= yaffsfs_FollowLink(obj
, 0, &loop
);
2079 yaffsfs_SetError(-ENOTDIR
);
2081 yaffsfs_SetError(-ELOOP
);
2082 else if (!dir
|| !obj
)
2083 yaffsfs_SetError(-ENOENT
);
2085 retVal
= yaffs_remove_xattrib(obj
, name
);
2087 yaffsfs_SetError(retVal
);
2098 int yaffs_removexattr(const YCHAR
*path
, const char *name
)
2100 return yaffs_do_removexattr(path
, name
, 1);
2103 int yaffs_lremovexattr(const YCHAR
*path
, const char *name
)
2105 return yaffs_do_removexattr(path
, name
, 0);
2108 int yaffs_fremovexattr(int fd
, const char *name
)
2110 struct yaffs_obj
*obj
;
2115 yaffsfs_SetError(-EFAULT
);
2120 obj
= yaffsfs_HandleToObject(fd
);
2123 retVal
= yaffs_remove_xattrib(obj
, name
);
2125 yaffsfs_SetError(retVal
);
2130 yaffsfs_SetError(-EBADF
);
2138 #ifdef CONFIG_YAFFS_WINCE
2139 int yaffs_get_wince_times(int fd
, unsigned *wctime
,
2140 unsigned *watime
, unsigned *wmtime
)
2142 struct yaffs_obj
*obj
;
2147 obj
= yaffsfs_HandleToObject(fd
);
2152 wctime
[0] = obj
->win_ctime
[0];
2153 wctime
[1] = obj
->win_ctime
[1];
2156 watime
[0] = obj
->win_atime
[0];
2157 watime
[1] = obj
->win_atime
[1];
2160 wmtime
[0] = obj
->win_mtime
[0];
2161 wmtime
[1] = obj
->win_mtime
[1];
2167 yaffsfs_SetError(-EBADF
);
2174 int yaffs_set_wince_times(int fd
,
2175 const unsigned *wctime
,
2176 const unsigned *watime
, const unsigned *wmtime
)
2178 struct yaffs_obj
*obj
;
2183 obj
= yaffsfs_HandleToObject(fd
);
2188 obj
->win_ctime
[0] = wctime
[0];
2189 obj
->win_ctime
[1] = wctime
[1];
2192 obj
->win_atime
[0] = watime
[0];
2193 obj
->win_atime
[1] = watime
[1];
2196 obj
->win_mtime
[0] = wmtime
[0];
2197 obj
->win_mtime
[1] = wmtime
[1];
2201 result
= yaffs_flush_file(obj
, 0, 0);
2205 yaffsfs_SetError(-EBADF
);
2214 static int yaffsfs_DoChMod(struct yaffs_obj
*obj
, mode_t mode
)
2219 obj
= yaffs_get_equivalent_obj(obj
);
2222 obj
->yst_mode
= mode
;
2224 result
= yaffs_flush_file(obj
, 0, 0);
2227 return result
== YAFFS_OK
? 0 : -1;
2230 int yaffs_access(const YCHAR
*path
, int amode
)
2232 struct yaffs_obj
*obj
= NULL
;
2233 struct yaffs_obj
*dir
= NULL
;
2239 yaffsfs_SetError(-EFAULT
);
2243 if (yaffsfs_CheckPath(path
) < 0) {
2244 yaffsfs_SetError(-ENAMETOOLONG
);
2248 if (amode
& ~(R_OK
| W_OK
| X_OK
)) {
2249 yaffsfs_SetError(-EINVAL
);
2255 obj
= yaffsfs_FindObject(NULL
, path
, 0, 1, &dir
, ¬Dir
, &loop
);
2256 obj
= yaffsfs_FollowLink(obj
, 0, &loop
);
2259 yaffsfs_SetError(-ENOTDIR
);
2261 yaffsfs_SetError(-ELOOP
);
2262 else if (!dir
|| !obj
)
2263 yaffsfs_SetError(-ENOENT
);
2264 else if ((amode
& W_OK
) && obj
->my_dev
->read_only
)
2265 yaffsfs_SetError(-EROFS
);
2269 if ((amode
& R_OK
) && !(obj
->yst_mode
& S_IREAD
))
2271 if ((amode
& W_OK
) && !(obj
->yst_mode
& S_IWRITE
))
2273 if ((amode
& X_OK
) && !(obj
->yst_mode
& S_IEXEC
))
2277 yaffsfs_SetError(-EACCES
);
2288 int yaffs_chmod(const YCHAR
*path
, mode_t mode
)
2290 struct yaffs_obj
*obj
= NULL
;
2291 struct yaffs_obj
*dir
= NULL
;
2297 yaffsfs_SetError(-EFAULT
);
2301 if (yaffsfs_CheckPath(path
) < 0) {
2302 yaffsfs_SetError(-ENAMETOOLONG
);
2306 if (mode
& ~(0777)) {
2307 yaffsfs_SetError(-EINVAL
);
2313 obj
= yaffsfs_FindObject(NULL
, path
, 0, 1, &dir
, ¬Dir
, &loop
);
2314 obj
= yaffsfs_FollowLink(obj
, 0, &loop
);
2317 yaffsfs_SetError(-ENOTDIR
);
2319 yaffsfs_SetError(-ELOOP
);
2320 else if (!dir
|| !obj
)
2321 yaffsfs_SetError(-ENOENT
);
2322 else if (obj
->my_dev
->read_only
)
2323 yaffsfs_SetError(-EROFS
);
2325 retVal
= yaffsfs_DoChMod(obj
, mode
);
2333 int yaffs_fchmod(int fd
, mode_t mode
)
2335 struct yaffs_obj
*obj
;
2338 if (mode
& ~(0777)) {
2339 yaffsfs_SetError(-EINVAL
);
2344 obj
= yaffsfs_HandleToObject(fd
);
2347 yaffsfs_SetError(-EBADF
);
2348 else if (obj
->my_dev
->read_only
)
2349 yaffsfs_SetError(-EROFS
);
2351 retVal
= yaffsfs_DoChMod(obj
, mode
);
2358 int yaffs_mkdir(const YCHAR
*path
, mode_t mode
)
2360 struct yaffs_obj
*parent
= NULL
;
2361 struct yaffs_obj
*dir
= NULL
;
2363 YCHAR
*alt_path
= NULL
;
2369 yaffsfs_SetError(-EFAULT
);
2373 if (yaffsfs_CheckPath(path
) < 0) {
2374 yaffsfs_SetError(-ENAMETOOLONG
);
2378 if (yaffsfs_alt_dir_path(path
, &alt_path
) < 0) {
2379 yaffsfs_SetError(-ENOMEM
);
2386 parent
= yaffsfs_FindDirectory(NULL
, path
, &name
, 0, ¬Dir
, &loop
);
2387 if (!parent
&& notDir
)
2388 yaffsfs_SetError(-ENOTDIR
);
2390 yaffsfs_SetError(-ELOOP
);
2392 yaffsfs_SetError(-ENOENT
);
2393 else if (yaffsfs_TooManyObjects(parent
->my_dev
))
2394 yaffsfs_SetError(-ENFILE
);
2395 else if (yaffs_strnlen(name
, 5) == 0) {
2396 /* Trying to make the root itself */
2397 yaffsfs_SetError(-EEXIST
);
2398 } else if (parent
->my_dev
->read_only
)
2399 yaffsfs_SetError(-EROFS
);
2401 dir
= yaffs_create_dir(parent
, name
, mode
, 0, 0);
2404 else if (yaffs_find_by_name(parent
, name
))
2405 yaffsfs_SetError(-EEXIST
); /* name exists */
2407 yaffsfs_SetError(-ENOSPC
); /* assume no space */
2417 int yaffs_rmdir(const YCHAR
*path
)
2423 yaffsfs_SetError(-EFAULT
);
2427 if (yaffsfs_CheckPath(path
) < 0) {
2428 yaffsfs_SetError(-ENAMETOOLONG
);
2432 if (yaffsfs_alt_dir_path(path
, &alt_path
) < 0) {
2433 yaffsfs_SetError(-ENOMEM
);
2438 result
= yaffsfs_DoUnlink(path
, 1);
2445 void *yaffs_getdev(const YCHAR
*path
)
2447 struct yaffs_dev
*dev
= NULL
;
2449 dev
= yaffsfs_FindDevice(path
, &dummy
);
2453 int yaffs_mount_common(const YCHAR
*path
, int read_only
, int skip_checkpt
)
2456 int result
= YAFFS_FAIL
;
2457 struct yaffs_dev
*dev
= NULL
;
2460 yaffsfs_SetError(-EFAULT
);
2464 yaffs_trace(YAFFS_TRACE_MOUNT
, "yaffs: Mounting %s", path
);
2466 if (yaffsfs_CheckPath(path
) < 0) {
2467 yaffsfs_SetError(-ENAMETOOLONG
);
2473 yaffsfs_InitHandles();
2475 dev
= yaffsfs_FindMountPoint(path
);
2477 if (!dev
->is_mounted
) {
2478 dev
->read_only
= read_only
? 1 : 0;
2480 u8 skip
= dev
->param
.skip_checkpt_rd
;
2481 dev
->param
.skip_checkpt_rd
= 1;
2482 result
= yaffs_guts_initialise(dev
);
2483 dev
->param
.skip_checkpt_rd
= skip
;
2485 result
= yaffs_guts_initialise(dev
);
2488 if (result
== YAFFS_FAIL
)
2489 yaffsfs_SetError(-ENOMEM
);
2490 retVal
= result
? 0 : -1;
2493 yaffsfs_SetError(-EBUSY
);
2495 yaffsfs_SetError(-ENODEV
);
2502 int yaffs_mount2(const YCHAR
*path
, int readonly
)
2504 return yaffs_mount_common(path
, readonly
, 0);
2507 int yaffs_mount(const YCHAR
*path
)
2509 return yaffs_mount_common(path
, 0, 0);
2512 int yaffs_sync(const YCHAR
*path
)
2515 struct yaffs_dev
*dev
= NULL
;
2519 yaffsfs_SetError(-EFAULT
);
2523 if (yaffsfs_CheckPath(path
) < 0) {
2524 yaffsfs_SetError(-ENAMETOOLONG
);
2529 dev
= yaffsfs_FindDevice(path
, &dummy
);
2531 if (!dev
->is_mounted
)
2532 yaffsfs_SetError(-EINVAL
);
2533 else if (dev
->read_only
)
2534 yaffsfs_SetError(-EROFS
);
2537 yaffs_flush_whole_cache(dev
);
2538 yaffs_checkpoint_save(dev
);
2543 yaffsfs_SetError(-ENODEV
);
2549 static int yaffsfs_IsDevBusy(struct yaffs_dev
*dev
)
2552 struct yaffs_obj
*obj
;
2554 for (i
= 0; i
< YAFFSFS_N_HANDLES
; i
++) {
2555 obj
= yaffsfs_HandleToObject(i
);
2556 if (obj
&& obj
->my_dev
== dev
)
2562 int yaffs_remount(const YCHAR
*path
, int force
, int read_only
)
2565 struct yaffs_dev
*dev
= NULL
;
2568 yaffsfs_SetError(-EFAULT
);
2572 if (yaffsfs_CheckPath(path
) < 0) {
2573 yaffsfs_SetError(-ENAMETOOLONG
);
2578 dev
= yaffsfs_FindMountPoint(path
);
2580 if (dev
->is_mounted
) {
2581 yaffs_flush_whole_cache(dev
);
2583 if (force
|| !yaffsfs_IsDevBusy(dev
)) {
2585 yaffs_checkpoint_save(dev
);
2586 dev
->read_only
= read_only
? 1 : 0;
2589 yaffsfs_SetError(-EBUSY
);
2592 yaffsfs_SetError(-EINVAL
);
2595 yaffsfs_SetError(-ENODEV
);
2602 int yaffs_unmount2(const YCHAR
*path
, int force
)
2605 struct yaffs_dev
*dev
= NULL
;
2608 yaffsfs_SetError(-EFAULT
);
2612 if (yaffsfs_CheckPath(path
) < 0) {
2613 yaffsfs_SetError(-ENAMETOOLONG
);
2618 dev
= yaffsfs_FindMountPoint(path
);
2620 if (dev
->is_mounted
) {
2622 yaffs_flush_whole_cache(dev
);
2623 yaffs_checkpoint_save(dev
);
2624 inUse
= yaffsfs_IsDevBusy(dev
);
2625 if (!inUse
|| force
) {
2627 yaffsfs_BreakDeviceHandles(dev
);
2628 yaffs_deinitialise(dev
);
2632 yaffsfs_SetError(-EBUSY
);
2635 yaffsfs_SetError(-EINVAL
);
2638 yaffsfs_SetError(-ENODEV
);
2645 int yaffs_unmount(const YCHAR
*path
)
2647 return yaffs_unmount2(path
, 0);
2650 loff_t
yaffs_freespace(const YCHAR
*path
)
2653 struct yaffs_dev
*dev
= NULL
;
2657 yaffsfs_SetError(-EFAULT
);
2661 if (yaffsfs_CheckPath(path
) < 0) {
2662 yaffsfs_SetError(-ENAMETOOLONG
);
2667 dev
= yaffsfs_FindDevice(path
, &dummy
);
2668 if (dev
&& dev
->is_mounted
) {
2669 retVal
= yaffs_get_n_free_chunks(dev
);
2670 retVal
*= dev
->data_bytes_per_chunk
;
2673 yaffsfs_SetError(-EINVAL
);
2679 loff_t
yaffs_totalspace(const YCHAR
*path
)
2682 struct yaffs_dev
*dev
= NULL
;
2686 yaffsfs_SetError(-EFAULT
);
2690 if (yaffsfs_CheckPath(path
) < 0) {
2691 yaffsfs_SetError(-ENAMETOOLONG
);
2696 dev
= yaffsfs_FindDevice(path
, &dummy
);
2697 if (dev
&& dev
->is_mounted
) {
2698 retVal
= (dev
->param
.end_block
- dev
->param
.start_block
+ 1) -
2699 dev
->param
.n_reserved_blocks
;
2700 retVal
*= dev
->param
.chunks_per_block
;
2701 retVal
*= dev
->data_bytes_per_chunk
;
2704 yaffsfs_SetError(-EINVAL
);
2710 int yaffs_inodecount(const YCHAR
*path
)
2713 struct yaffs_dev
*dev
= NULL
;
2717 yaffsfs_SetError(-EFAULT
);
2721 if (yaffsfs_CheckPath(path
) < 0) {
2722 yaffsfs_SetError(-ENAMETOOLONG
);
2727 dev
= yaffsfs_FindDevice(path
, &dummy
);
2728 if (dev
&& dev
->is_mounted
) {
2729 int n_obj
= dev
->n_obj
;
2730 if (n_obj
> dev
->n_hardlinks
)
2731 retVal
= n_obj
- dev
->n_hardlinks
;
2735 yaffsfs_SetError(-EINVAL
);
2741 void yaffs_add_device(struct yaffs_dev
*dev
)
2743 struct list_head
*cfg
;
2744 /* First check that the device is not in the list. */
2746 list_for_each(cfg
, &yaffsfs_deviceList
) {
2747 if (dev
== list_entry(cfg
, struct yaffs_dev
, dev_list
))
2751 dev
->is_mounted
= 0;
2752 dev
->param
.remove_obj_fn
= yaffsfs_RemoveObjectCallback
;
2754 if (!dev
->dev_list
.next
)
2755 INIT_LIST_HEAD(&dev
->dev_list
);
2757 list_add(&dev
->dev_list
, &yaffsfs_deviceList
);
2760 void yaffs_remove_device(struct yaffs_dev
*dev
)
2762 list_del_init(&dev
->dev_list
);
2765 /* Functions to iterate through devices. NB Use with extreme care! */
2767 static struct list_head
*dev_iterator
;
2768 void yaffs_dev_rewind(void)
2770 dev_iterator
= yaffsfs_deviceList
.next
;
2773 struct yaffs_dev
*yaffs_next_dev(void)
2775 struct yaffs_dev
*retval
;
2779 if (dev_iterator
== &yaffsfs_deviceList
)
2782 retval
= list_entry(dev_iterator
, struct yaffs_dev
, dev_list
);
2783 dev_iterator
= dev_iterator
->next
;
2787 /* Directory search stuff. */
2789 static struct list_head search_contexts
;
2791 static void yaffsfs_SetDirRewound(struct yaffsfs_DirSearchContxt
*dsc
)
2795 dsc
->dirObj
->variant_type
== YAFFS_OBJECT_TYPE_DIRECTORY
) {
2799 if (list_empty(&dsc
->dirObj
->variant
.dir_variant
.children
))
2800 dsc
->nextReturn
= NULL
;
2803 list_entry(dsc
->dirObj
->variant
.dir_variant
.
2804 children
.next
, struct yaffs_obj
,
2807 /* Hey someone isn't playing nice! */
2811 static void yaffsfs_DirAdvance(struct yaffsfs_DirSearchContxt
*dsc
)
2815 dsc
->dirObj
->variant_type
== YAFFS_OBJECT_TYPE_DIRECTORY
) {
2817 if (dsc
->nextReturn
== NULL
||
2818 list_empty(&dsc
->dirObj
->variant
.dir_variant
.children
))
2819 dsc
->nextReturn
= NULL
;
2821 struct list_head
*next
= dsc
->nextReturn
->siblings
.next
;
2823 if (next
== &dsc
->dirObj
->variant
.dir_variant
.children
)
2824 dsc
->nextReturn
= NULL
; /* end of list */
2826 dsc
->nextReturn
= list_entry(next
,
2831 /* Hey someone isn't playing nice! */
2835 static void yaffsfs_RemoveObjectCallback(struct yaffs_obj
*obj
)
2838 struct list_head
*i
;
2839 struct yaffsfs_DirSearchContxt
*dsc
;
2841 /* if search contexts not initilised then skip */
2842 if (!search_contexts
.next
)
2845 /* Iterate through the directory search contexts.
2846 * If any are the one being removed, then advance the dsc to
2847 * the next one to prevent a hanging ptr.
2849 list_for_each(i
, &search_contexts
) {
2851 dsc
= list_entry(i
, struct yaffsfs_DirSearchContxt
,
2853 if (dsc
->nextReturn
== obj
)
2854 yaffsfs_DirAdvance(dsc
);
2860 yaffs_DIR
*yaffs_opendir(const YCHAR
*dirname
)
2862 yaffs_DIR
*dir
= NULL
;
2863 struct yaffs_obj
*obj
= NULL
;
2864 struct yaffsfs_DirSearchContxt
*dsc
= NULL
;
2869 yaffsfs_SetError(-EFAULT
);
2873 if (yaffsfs_CheckPath(dirname
) < 0) {
2874 yaffsfs_SetError(-ENAMETOOLONG
);
2880 obj
= yaffsfs_FindObject(NULL
, dirname
, 0, 1, NULL
, ¬Dir
, &loop
);
2883 yaffsfs_SetError(-ENOTDIR
);
2885 yaffsfs_SetError(-ELOOP
);
2887 yaffsfs_SetError(-ENOENT
);
2888 else if (obj
->variant_type
!= YAFFS_OBJECT_TYPE_DIRECTORY
)
2889 yaffsfs_SetError(-ENOTDIR
);
2893 for (i
= 0, dsc
= NULL
; i
< YAFFSFS_N_DSC
&& !dsc
; i
++) {
2894 if (!yaffsfs_dsc
[i
].inUse
)
2895 dsc
= &yaffsfs_dsc
[i
];
2898 dir
= (yaffs_DIR
*) dsc
;
2901 memset(dsc
, 0, sizeof(struct yaffsfs_DirSearchContxt
));
2904 yaffs_strncpy(dsc
->name
, dirname
, NAME_MAX
);
2905 INIT_LIST_HEAD(&dsc
->others
);
2907 if (!search_contexts
.next
)
2908 INIT_LIST_HEAD(&search_contexts
);
2910 list_add(&dsc
->others
, &search_contexts
);
2911 yaffsfs_SetDirRewound(dsc
);
2921 struct yaffs_dirent
*yaffs_readdir(yaffs_DIR
* dirp
)
2923 struct yaffsfs_DirSearchContxt
*dsc
;
2924 struct yaffs_dirent
*retVal
= NULL
;
2926 dsc
= (struct yaffsfs_DirSearchContxt
*) dirp
;
2929 if (dsc
&& dsc
->inUse
) {
2930 yaffsfs_SetError(0);
2931 if (dsc
->nextReturn
) {
2933 yaffs_get_equivalent_obj(dsc
->nextReturn
)->obj_id
;
2934 dsc
->de
.d_dont_use
= (unsigned)dsc
->nextReturn
;
2935 dsc
->de
.d_off
= dsc
->offset
++;
2936 yaffs_get_obj_name(dsc
->nextReturn
,
2937 dsc
->de
.d_name
, NAME_MAX
);
2938 if (yaffs_strnlen(dsc
->de
.d_name
, NAME_MAX
+ 1) == 0) {
2939 /* this should not happen! */
2940 yaffs_strcpy(dsc
->de
.d_name
, _Y("zz"));
2942 dsc
->de
.d_reclen
= sizeof(struct yaffs_dirent
);
2944 yaffsfs_DirAdvance(dsc
);
2948 yaffsfs_SetError(-EBADF
);
2956 void yaffs_rewinddir(yaffs_DIR
*dirp
)
2958 struct yaffsfs_DirSearchContxt
*dsc
;
2960 dsc
= (struct yaffsfs_DirSearchContxt
*) dirp
;
2964 yaffsfs_SetDirRewound(dsc
);
2969 int yaffs_closedir(yaffs_DIR
*dirp
)
2971 struct yaffsfs_DirSearchContxt
*dsc
;
2973 dsc
= (struct yaffsfs_DirSearchContxt
*) dirp
;
2976 yaffsfs_SetError(-EFAULT
);
2982 list_del(&dsc
->others
); /* unhook from list */
2987 /* End of directory stuff */
2989 int yaffs_symlink(const YCHAR
*oldpath
, const YCHAR
*newpath
)
2991 struct yaffs_obj
*parent
= NULL
;
2992 struct yaffs_obj
*obj
;
2995 int mode
= 0; /* ignore for now */
2999 if (!oldpath
|| !newpath
) {
3000 yaffsfs_SetError(-EFAULT
);
3004 if (yaffsfs_CheckPath(newpath
) < 0 || yaffsfs_CheckPath(oldpath
) < 0) {
3005 yaffsfs_SetError(-ENAMETOOLONG
);
3010 parent
= yaffsfs_FindDirectory(NULL
, newpath
, &name
, 0, ¬Dir
, &loop
);
3011 if (!parent
&& notDir
)
3012 yaffsfs_SetError(-ENOTDIR
);
3014 yaffsfs_SetError(-ELOOP
);
3015 else if (!parent
|| yaffs_strnlen(name
, 5) < 1)
3016 yaffsfs_SetError(-ENOENT
);
3017 else if (yaffsfs_TooManyObjects(parent
->my_dev
))
3018 yaffsfs_SetError(-ENFILE
);
3019 else if (parent
->my_dev
->read_only
)
3020 yaffsfs_SetError(-EROFS
);
3022 obj
= yaffs_create_symlink(parent
, name
, mode
, 0, 0, oldpath
);
3025 else if (yaffsfs_FindObject
3026 (NULL
, newpath
, 0, 0, NULL
, NULL
, NULL
))
3027 yaffsfs_SetError(-EEXIST
);
3029 yaffsfs_SetError(-ENOSPC
);
3038 int yaffs_readlink(const YCHAR
*path
, YCHAR
*buf
, int bufsiz
)
3040 struct yaffs_obj
*obj
= NULL
;
3041 struct yaffs_obj
*dir
= NULL
;
3046 if (!path
|| !buf
) {
3047 yaffsfs_SetError(-EFAULT
);
3053 obj
= yaffsfs_FindObject(NULL
, path
, 0, 1, &dir
, ¬Dir
, &loop
);
3056 yaffsfs_SetError(-ENOTDIR
);
3058 yaffsfs_SetError(-ELOOP
);
3059 else if (!dir
|| !obj
)
3060 yaffsfs_SetError(-ENOENT
);
3061 else if (obj
->variant_type
!= YAFFS_OBJECT_TYPE_SYMLINK
)
3062 yaffsfs_SetError(-EINVAL
);
3064 YCHAR
*alias
= obj
->variant
.symlink_variant
.alias
;
3065 memset(buf
, 0, bufsiz
);
3066 yaffs_strncpy(buf
, alias
, bufsiz
- 1);
3073 int yaffs_link(const YCHAR
*oldpath
, const YCHAR
*linkpath
)
3075 /* Creates a link called newpath to existing oldpath */
3076 struct yaffs_obj
*obj
= NULL
;
3077 struct yaffs_obj
*lnk
= NULL
;
3078 struct yaffs_obj
*obj_dir
= NULL
;
3079 struct yaffs_obj
*lnk_dir
= NULL
;
3087 if (!oldpath
|| !linkpath
) {
3088 yaffsfs_SetError(-EFAULT
);
3092 if (yaffsfs_CheckPath(linkpath
) < 0 || yaffsfs_CheckPath(oldpath
) < 0) {
3093 yaffsfs_SetError(-ENAMETOOLONG
);
3099 obj
= yaffsfs_FindObject(NULL
, oldpath
, 0, 1,
3100 &obj_dir
, ¬DirObj
, &objLoop
);
3101 lnk
= yaffsfs_FindObject(NULL
, linkpath
, 0, 0, NULL
, NULL
, NULL
);
3102 lnk_dir
= yaffsfs_FindDirectory(NULL
, linkpath
, &newname
,
3103 0, ¬DirLnk
, &lnkLoop
);
3105 if ((!obj_dir
&& notDirObj
) || (!lnk_dir
&& notDirLnk
))
3106 yaffsfs_SetError(-ENOTDIR
);
3107 else if (objLoop
|| lnkLoop
)
3108 yaffsfs_SetError(-ELOOP
);
3109 else if (!obj_dir
|| !lnk_dir
|| !obj
)
3110 yaffsfs_SetError(-ENOENT
);
3111 else if (obj
->my_dev
->read_only
)
3112 yaffsfs_SetError(-EROFS
);
3113 else if (yaffsfs_TooManyObjects(obj
->my_dev
))
3114 yaffsfs_SetError(-ENFILE
);
3116 yaffsfs_SetError(-EEXIST
);
3117 else if (lnk_dir
->my_dev
!= obj
->my_dev
)
3118 yaffsfs_SetError(-EXDEV
);
3120 retVal
= yaffsfs_CheckNameLength(newname
);
3123 lnk
= yaffs_link_obj(lnk_dir
, newname
, obj
);
3127 yaffsfs_SetError(-ENOSPC
);
3137 int yaffs_mknod(const YCHAR
*pathname
, mode_t mode
, dev_t dev
)
3139 yaffsfs_SetError(-EINVAL
);
3144 * D E B U G F U N C T I O N S
3149 * Returns number of handles attached to the object
3151 int yaffs_n_handles(const YCHAR
*path
)
3153 struct yaffs_obj
*obj
;
3156 yaffsfs_SetError(-EFAULT
);
3160 if (yaffsfs_CheckPath(path
) < 0) {
3161 yaffsfs_SetError(-ENAMETOOLONG
);
3165 obj
= yaffsfs_FindObject(NULL
, path
, 0, 1, NULL
, NULL
, NULL
);
3168 return yaffsfs_CountHandles(obj
);
3173 int yaffs_get_error(void)
3175 return yaffsfs_GetLastError();
3178 int yaffs_set_error(int error
)
3180 yaffsfs_SetError(error
);
3184 int yaffs_dump_dev(const YCHAR
*path
)
3189 struct yaffs_obj
*obj
= yaffsfs_FindRoot(path
, &rest
);
3192 struct yaffs_dev
*dev
= obj
->my_dev
;
3195 "n_page_writes.......... %d\n"
3196 "n_page_reads........... %d\n"
3197 "n_erasures....... %d\n"
3198 "n_gc_copies............ %d\n"
3199 "garbageCollections... %d\n"
3200 "passiveGarbageColl'ns %d\n"
3206 dev
->garbageCollections
, dev
->passiveGarbageCollections
);