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.
15 #include "yaffs_guts.h"
18 #include "yaffs_trace.h"
20 #define YAFFSFS_MAX_SYMLINK_DEREFERENCES 5
23 #define NULL ((void *)0)
26 /* YAFFSFS_RW_SIZE must be a power of 2 */
27 #define YAFFSFS_RW_SHIFT (13)
28 #define YAFFSFS_RW_SIZE (1<<YAFFSFS_RW_SHIFT)
30 /* Some forward references */
31 static struct yaffs_obj
*yaffsfs_FindObject(struct yaffs_obj
*relativeDirectory
,
33 int symDepth
, int getEquiv
,
34 struct yaffs_obj
**dirOut
,
35 int *notDir
, int *loop
);
37 static void yaffsfs_RemoveObjectCallback(struct yaffs_obj
*obj
);
39 unsigned int yaffs_wr_attempts
;
43 * There are open inodes in struct yaffsfs_Inode.
44 * There are open file descriptors in yaffsfs_FileDes.
45 * There are open handles in yaffsfs_FileDes.
47 * Things are structured this way to be like the Linux VFS model
48 * so that interactions with the yaffs guts calls are similar.
49 * That means more common code paths and less special code.
50 * That means better testing etc.
52 * We have 3 layers because:
53 * A handle is different than an fd because you can use dup()
54 * to create a new handle that accesses the *same* fd. The two
55 * handles will use the same offset (part of the fd). We only close
56 * down the fd when there are no more handles accessing it.
58 * More than one fd can currently access one file, but each fd
59 * has its own permsiions and offset.
62 struct yaffsfs_Inode
{
63 int count
; /* Number of handles accessing this inode */
64 struct yaffs_obj
*iObj
;
67 struct yaffsfs_FileDes
{
73 int inodeId
:12; /* Index to corresponding yaffsfs_Inode */
74 int handleCount
:10; /* Number of handles for this fd */
75 loff_t position
; /* current position in file */
78 struct yaffsfs_Handle
{
84 struct yaffsfs_DirSearchContxt
{
85 struct yaffs_dirent de
; /* directory entry */
86 YCHAR name
[NAME_MAX
+ 1]; /* name of directory being searched */
87 struct yaffs_obj
*dirObj
; /* ptr to directory being searched */
88 struct yaffs_obj
*nextReturn
; /* obj returned by next readddir */
89 struct list_head others
;
94 static struct yaffsfs_DirSearchContxt yaffsfs_dsc
[YAFFSFS_N_DSC
];
95 static struct yaffsfs_Inode yaffsfs_inode
[YAFFSFS_N_HANDLES
];
96 static struct yaffsfs_FileDes yaffsfs_fd
[YAFFSFS_N_HANDLES
];
97 static struct yaffsfs_Handle yaffsfs_handle
[YAFFSFS_N_HANDLES
];
99 static int yaffsfs_handlesInitialised
;
101 unsigned yaffs_set_trace(unsigned tm
)
103 yaffs_trace_mask
= tm
;
104 return yaffs_trace_mask
;
107 unsigned yaffs_get_trace(void)
109 return yaffs_trace_mask
;
114 * Inilitalise handle management on start-up.
117 static void yaffsfs_InitHandles(void)
120 if (yaffsfs_handlesInitialised
)
123 memset(yaffsfs_inode
, 0, sizeof(yaffsfs_inode
));
124 memset(yaffsfs_fd
, 0, sizeof(yaffsfs_fd
));
125 memset(yaffsfs_handle
, 0, sizeof(yaffsfs_handle
));
126 memset(yaffsfs_dsc
, 0, sizeof(yaffsfs_dsc
));
128 for (i
= 0; i
< YAFFSFS_N_HANDLES
; i
++)
129 yaffsfs_fd
[i
].inodeId
= -1;
130 for (i
= 0; i
< YAFFSFS_N_HANDLES
; i
++)
131 yaffsfs_handle
[i
].fdId
= -1;
134 static struct yaffsfs_Handle
*yaffsfs_HandleToPointer(int h
)
136 if (h
>= 0 && h
< YAFFSFS_N_HANDLES
)
137 return &yaffsfs_handle
[h
];
141 static struct yaffsfs_FileDes
*yaffsfs_HandleToFileDes(int handle
)
143 struct yaffsfs_Handle
*h
= yaffsfs_HandleToPointer(handle
);
145 if (h
&& h
->useCount
> 0 && h
->fdId
>= 0 && h
->fdId
< YAFFSFS_N_HANDLES
)
146 return &yaffsfs_fd
[h
->fdId
];
151 static struct yaffsfs_Inode
*yaffsfs_HandleToInode(int handle
)
153 struct yaffsfs_FileDes
*fd
= yaffsfs_HandleToFileDes(handle
);
155 if (fd
&& fd
->handleCount
> 0 &&
156 fd
->inodeId
>= 0 && fd
->inodeId
< YAFFSFS_N_HANDLES
)
157 return &yaffsfs_inode
[fd
->inodeId
];
162 static struct yaffs_obj
*yaffsfs_HandleToObject(int handle
)
164 struct yaffsfs_Inode
*in
= yaffsfs_HandleToInode(handle
);
173 * yaffsfs_FindInodeIdForObject
174 * Find the inode entry for an object, if it exists.
177 static int yaffsfs_FindInodeIdForObject(struct yaffs_obj
*obj
)
183 obj
= yaffs_get_equivalent_obj(obj
);
185 /* Look for it in open inode table */
186 for (i
= 0; i
< YAFFSFS_N_HANDLES
&& ret
< 0; i
++) {
187 if (yaffsfs_inode
[i
].iObj
== obj
)
194 * yaffsfs_GetInodeIdForObject
195 * Grab an inode entry when opening a new inode.
197 static int yaffsfs_GetInodeIdForObject(struct yaffs_obj
*obj
)
201 struct yaffsfs_Inode
*in
= NULL
;
204 obj
= yaffs_get_equivalent_obj(obj
);
206 ret
= yaffsfs_FindInodeIdForObject(obj
);
208 for (i
= 0; i
< YAFFSFS_N_HANDLES
&& ret
< 0; i
++) {
209 if (!yaffsfs_inode
[i
].iObj
)
214 in
= &yaffsfs_inode
[ret
];
224 static int yaffsfs_CountHandles(struct yaffs_obj
*obj
)
226 int i
= yaffsfs_FindInodeIdForObject(obj
);
229 return yaffsfs_inode
[i
].count
;
234 static void yaffsfs_ReleaseInode(struct yaffsfs_Inode
*in
)
236 struct yaffs_obj
*obj
;
243 obj
->my_inode
= NULL
;
248 static void yaffsfs_PutInode(int inodeId
)
250 if (inodeId
>= 0 && inodeId
< YAFFSFS_N_HANDLES
) {
251 struct yaffsfs_Inode
*in
= &yaffsfs_inode
[inodeId
];
253 if (in
->count
<= 0) {
254 yaffsfs_ReleaseInode(in
);
260 static int yaffsfs_NewHandle(struct yaffsfs_Handle
**hptr
)
263 struct yaffsfs_Handle
*h
;
265 for (i
= 0; i
< YAFFSFS_N_HANDLES
; i
++) {
266 h
= &yaffsfs_handle
[i
];
267 if (h
->useCount
< 1) {
268 memset(h
, 0, sizeof(struct yaffsfs_Handle
));
279 static int yaffsfs_NewHandleAndFileDes(void)
282 struct yaffsfs_FileDes
*fd
;
283 struct yaffsfs_Handle
*h
= NULL
;
284 int handle
= yaffsfs_NewHandle(&h
);
289 for (i
= 0; i
< YAFFSFS_N_HANDLES
; i
++) {
291 if (fd
->handleCount
< 1) {
292 memset(fd
, 0, sizeof(struct yaffsfs_FileDes
));
300 /* Dump the handle because we could not get a fd */
307 * Increase use of handle when reading/writing a file
308 * Also gets the file descriptor.
311 static int yaffsfs_GetHandle(int handle
)
313 struct yaffsfs_Handle
*h
= yaffsfs_HandleToPointer(handle
);
315 if (h
&& h
->useCount
> 0) {
324 * Let go of a handle when closing a file or aborting an open or
325 * ending a read or write.
328 static int yaffsfs_PutFileDes(int fdId
)
330 struct yaffsfs_FileDes
*fd
;
332 if (fdId
>= 0 && fdId
< YAFFSFS_N_HANDLES
) {
333 fd
= &yaffsfs_fd
[fdId
];
335 if (fd
->handleCount
< 1) {
336 if (fd
->inodeId
>= 0) {
337 yaffsfs_PutInode(fd
->inodeId
);
345 static int yaffsfs_PutHandle(int handle
)
347 struct yaffsfs_Handle
*h
= yaffsfs_HandleToPointer(handle
);
349 if (h
&& h
->useCount
> 0) {
351 if (h
->useCount
< 1) {
352 yaffsfs_PutFileDes(h
->fdId
);
360 static void yaffsfs_BreakDeviceHandles(struct yaffs_dev
*dev
)
362 struct yaffsfs_FileDes
*fd
;
363 struct yaffsfs_Handle
*h
;
364 struct yaffs_obj
*obj
;
366 for (i
= 0; i
< YAFFSFS_N_HANDLES
; i
++) {
367 h
= yaffsfs_HandleToPointer(i
);
368 fd
= yaffsfs_HandleToFileDes(i
);
369 obj
= yaffsfs_HandleToObject(i
);
370 if (h
&& h
->useCount
> 0) {
374 if (fd
&& fd
->handleCount
> 0 && obj
&& obj
->my_dev
== dev
) {
376 yaffsfs_PutInode(fd
->inodeId
);
383 * Stuff to handle names.
385 #ifdef CONFIG_YAFFS_CASE_INSENSITIVE
387 static int yaffs_toupper(YCHAR a
)
389 if (a
>= 'a' && a
<= 'z')
390 return (a
- 'a') + 'A';
395 int yaffsfs_Match(YCHAR a
, YCHAR b
)
397 return (yaffs_toupper(a
) == yaffs_toupper(b
));
400 int yaffsfs_Match(YCHAR a
, YCHAR b
)
407 int yaffsfs_IsPathDivider(YCHAR ch
)
409 const YCHAR
*str
= YAFFS_PATH_DIVIDERS
;
420 int yaffsfs_CheckNameLength(const char *name
)
424 int nameLength
= yaffs_strnlen(name
, YAFFS_MAX_NAME_LENGTH
+ 1);
426 if (nameLength
== 0) {
427 yaffsfs_SetError(-ENOENT
);
429 } else if (nameLength
> YAFFS_MAX_NAME_LENGTH
) {
430 yaffsfs_SetError(-ENAMETOOLONG
);
437 static int yaffsfs_alt_dir_path(const YCHAR
*path
, YCHAR
**ret_path
)
439 YCHAR
*alt_path
= NULL
;
444 * We don't have a definition for max path length.
445 * We will use 3 * max name length instead.
448 path_length
= yaffs_strnlen(path
, (YAFFS_MAX_NAME_LENGTH
+ 1) * 3 + 1);
450 /* If the last character is a path divider, then we need to
451 * trim it back so that the name look-up works properly.
452 * eg. /foo/new_dir/ -> /foo/newdir
453 * Curveball: Need to handle multiple path dividers:
454 * eg. /foof/sdfse///// -> /foo/sdfse
456 if (path_length
> 0 && yaffsfs_IsPathDivider(path
[path_length
- 1])) {
457 alt_path
= kmalloc(path_length
+ 1, 0);
460 yaffs_strcpy(alt_path
, path
);
461 for (i
= path_length
- 1;
462 i
>= 0 && yaffsfs_IsPathDivider(alt_path
[i
]); i
--)
463 alt_path
[i
] = (YCHAR
) 0;
465 *ret_path
= alt_path
;
469 LIST_HEAD(yaffsfs_deviceList
);
474 * Scan the configuration list to find the device
475 * Curveballs: Should match paths that end in '/' too
476 * Curveball2 Might have "/x/ and "/x/y". Need to return the longest match
478 static struct yaffs_dev
*yaffsfs_FindDevice(const YCHAR
*path
,
481 struct list_head
*cfg
;
482 const YCHAR
*leftOver
;
484 struct yaffs_dev
*retval
= NULL
;
485 struct yaffs_dev
*dev
= NULL
;
487 int longestMatch
= -1;
491 * Check all configs, choose the one that:
492 * 1) Actually matches a prefix (ie /a amd /abc will not match
493 * 2) Matches the longest.
495 list_for_each(cfg
, &yaffsfs_deviceList
) {
496 dev
= list_entry(cfg
, struct yaffs_dev
, dev_list
);
502 while (matching
&& *p
&& *leftOver
) {
503 /* Skip over any /s */
504 while (yaffsfs_IsPathDivider(*p
))
507 /* Skip over any /s */
508 while (yaffsfs_IsPathDivider(*leftOver
))
511 /* Now match the text part */
513 *p
&& !yaffsfs_IsPathDivider(*p
) &&
514 *leftOver
&& !yaffsfs_IsPathDivider(*leftOver
)) {
515 if (yaffsfs_Match(*p
, *leftOver
)) {
525 /* Skip over any /s in leftOver */
526 while (yaffsfs_IsPathDivider(*leftOver
))
529 /*Skip over any /s in p */
530 while (yaffsfs_IsPathDivider(*p
))
533 /* p should now be at the end of the string if fully matched */
537 if (matching
&& (thisMatchLength
> longestMatch
)) {
539 *restOfPath
= (YCHAR
*) leftOver
;
541 longestMatch
= thisMatchLength
;
548 static int yaffsfs_CheckPath(const YCHAR
*path
)
553 while (*path
&& n
< YAFFS_MAX_NAME_LENGTH
&& divs
< 100) {
554 if (yaffsfs_IsPathDivider(*path
)) {
562 return (*path
) ? -1 : 0;
565 /* FindMountPoint only returns a dev entry if the path is a mount point */
566 static struct yaffs_dev
*yaffsfs_FindMountPoint(const YCHAR
*path
)
568 struct yaffs_dev
*dev
;
569 YCHAR
*restOfPath
= NULL
;
571 dev
= yaffsfs_FindDevice(path
, &restOfPath
);
572 if (dev
&& restOfPath
&& *restOfPath
)
577 static struct yaffs_obj
*yaffsfs_FindRoot(const YCHAR
*path
,
580 struct yaffs_dev
*dev
;
582 dev
= yaffsfs_FindDevice(path
, restOfPath
);
583 if (dev
&& dev
->is_mounted
)
584 return dev
->root_dir
;
589 static struct yaffs_obj
*yaffsfs_FollowLink(struct yaffs_obj
*obj
,
590 int symDepth
, int *loop
)
594 obj
= yaffs_get_equivalent_obj(obj
);
596 while (obj
&& obj
->variant_type
== YAFFS_OBJECT_TYPE_SYMLINK
) {
597 YCHAR
*alias
= obj
->variant
.symlink_variant
.alias
;
599 if (yaffsfs_IsPathDivider(*alias
))
600 /* Starts with a /, need to scan from root up */
601 obj
= yaffsfs_FindObject(NULL
, alias
, symDepth
++,
602 1, NULL
, NULL
, loop
);
605 * Relative to here so use the parent of the
608 obj
= yaffsfs_FindObject(obj
->parent
, alias
, symDepth
++,
609 1, NULL
, NULL
, loop
);
615 * yaffsfs_FindDirectory
616 * Parse a path to determine the directory and the name within the directory.
618 * eg. "/data/xx/ff" --> puts name="ff" and returns the directory "/data/xx"
620 static struct yaffs_obj
*yaffsfs_DoFindDirectory(struct yaffs_obj
*startDir
,
622 YCHAR
**name
, int symDepth
,
623 int *notDir
, int *loop
)
625 struct yaffs_obj
*dir
;
627 YCHAR str
[YAFFS_MAX_NAME_LENGTH
+ 1];
630 if (symDepth
> YAFFSFS_MAX_SYMLINK_DEREFERENCES
) {
638 restOfPath
= (YCHAR
*) path
;
640 dir
= yaffsfs_FindRoot(path
, &restOfPath
);
645 * curve ball: also throw away surplus '/'
646 * eg. "/ram/x////ff" gets treated the same as "/ram/x/ff"
648 while (yaffsfs_IsPathDivider(*restOfPath
))
649 restOfPath
++; /* get rid of '/' */
654 while (*restOfPath
&& !yaffsfs_IsPathDivider(*restOfPath
)) {
655 if (i
< YAFFS_MAX_NAME_LENGTH
) {
656 str
[i
] = *restOfPath
;
664 /* got to the end of the string */
667 if (yaffs_strcmp(str
, _Y(".")) == 0) {
669 } else if (yaffs_strcmp(str
, _Y("..")) == 0) {
672 dir
= yaffs_find_by_name(dir
, str
);
674 dir
= yaffsfs_FollowLink(dir
, symDepth
, loop
);
676 if (dir
&& dir
->variant_type
!=
677 YAFFS_OBJECT_TYPE_DIRECTORY
) {
686 /* directory did not exist. */
690 static struct yaffs_obj
*yaffsfs_FindDirectory(struct yaffs_obj
*relDir
,
694 int *notDir
, int *loop
)
696 return yaffsfs_DoFindDirectory(relDir
, path
, name
, symDepth
, notDir
,
701 * yaffsfs_FindObject turns a path for an existing object into the object
703 static struct yaffs_obj
*yaffsfs_FindObject(struct yaffs_obj
*relDir
,
704 const YCHAR
*path
, int symDepth
,
706 struct yaffs_obj
**dirOut
,
707 int *notDir
, int *loop
)
709 struct yaffs_obj
*dir
;
710 struct yaffs_obj
*obj
;
714 yaffsfs_FindDirectory(relDir
, path
, &name
, symDepth
, notDir
, loop
);
720 obj
= yaffs_find_by_name(dir
, name
);
725 obj
= yaffs_get_equivalent_obj(obj
);
730 /*************************************************************************
731 * Start of yaffsfs visible functions.
732 *************************************************************************/
734 int yaffs_dup(int handle
)
736 int newHandleNumber
= -1;
737 struct yaffsfs_FileDes
*existingFD
= NULL
;
738 struct yaffsfs_Handle
*existingHandle
= NULL
;
739 struct yaffsfs_Handle
*newHandle
= NULL
;
742 existingHandle
= yaffsfs_HandleToPointer(handle
);
743 existingFD
= yaffsfs_HandleToFileDes(handle
);
745 newHandleNumber
= yaffsfs_NewHandle(&newHandle
);
747 newHandle
->fdId
= existingHandle
->fdId
;
748 existingFD
->handleCount
++;
754 yaffsfs_SetError(-EBADF
);
756 yaffsfs_SetError(-ENOMEM
);
758 return newHandleNumber
;
762 static int yaffsfs_TooManyObjects(struct yaffs_dev
*dev
)
764 int current_objects
= dev
->n_obj
- dev
->n_deleted_files
;
766 if (dev
->param
.max_objects
&& current_objects
> dev
->param
.max_objects
)
772 int yaffs_open_sharing(const YCHAR
*path
, int oflag
, int mode
, int sharing
)
774 struct yaffs_obj
*obj
= NULL
;
775 struct yaffs_obj
*dir
= NULL
;
778 struct yaffsfs_FileDes
*fd
= NULL
;
781 int errorReported
= 0;
782 int rwflags
= oflag
& (O_RDWR
| O_RDONLY
| O_WRONLY
);
783 u8 shareRead
= (sharing
& YAFFS_SHARE_READ
) ? 1 : 0;
784 u8 shareWrite
= (sharing
& YAFFS_SHARE_WRITE
) ? 1 : 0;
785 u8 sharedReadAllowed
;
786 u8 sharedWriteAllowed
;
795 yaffsfs_SetError(-EFAULT
);
799 if (yaffsfs_CheckPath(path
) < 0) {
800 yaffsfs_SetError(-ENAMETOOLONG
);
804 /* O_EXCL only has meaning if O_CREAT is specified */
805 if (!(oflag
& O_CREAT
))
808 /* O_TRUNC has no meaning if (O_CREAT | O_EXCL) is specified */
809 if ((oflag
& O_CREAT
) & (oflag
& O_EXCL
))
812 /* Todo: Are there any more flag combos to sanitise ? */
814 /* Figure out if reading or writing is requested */
816 readRequested
= (rwflags
== O_RDWR
|| rwflags
== O_RDONLY
) ? 1 : 0;
817 writeRequested
= (rwflags
== O_RDWR
|| rwflags
== O_WRONLY
) ? 1 : 0;
821 handle
= yaffsfs_NewHandleAndFileDes();
824 yaffsfs_SetError(-ENFILE
);
828 fd
= yaffsfs_HandleToFileDes(handle
);
830 /* try to find the exisiting object */
831 obj
= yaffsfs_FindObject(NULL
, path
, 0, 1, NULL
, NULL
, NULL
);
833 obj
= yaffsfs_FollowLink(obj
, symDepth
++, &loop
);
836 obj
->variant_type
!= YAFFS_OBJECT_TYPE_FILE
&&
837 obj
->variant_type
!= YAFFS_OBJECT_TYPE_DIRECTORY
)
842 /* The file already exists or it might be a directory */
844 /* A directory can't be opened as a file */
845 if (obj
->variant_type
== YAFFS_OBJECT_TYPE_DIRECTORY
) {
847 yaffsfs_SetError(-EISDIR
);
851 /* Open should fail if O_CREAT and O_EXCL are specified
852 * for a file that exists.
854 if (!errorReported
&&
855 (oflag
& O_EXCL
) && (oflag
& O_CREAT
)) {
857 yaffsfs_SetError(-EEXIST
);
861 /* Check file permissions */
862 if (readRequested
&& !(obj
->yst_mode
& S_IREAD
))
865 if (writeRequested
&& !(obj
->yst_mode
& S_IWRITE
))
868 if (!errorReported
&& writeRequested
&&
869 obj
->my_dev
->read_only
) {
871 yaffsfs_SetError(-EROFS
);
875 if (openDenied
&& !errorReported
) {
876 yaffsfs_SetError(-EACCES
);
880 /* Check sharing of an existing object. */
882 struct yaffsfs_FileDes
*fdx
;
885 sharedReadAllowed
= 1;
886 sharedWriteAllowed
= 1;
889 for (i
= 0; i
< YAFFSFS_N_HANDLES
; i
++) {
890 fdx
= &yaffsfs_fd
[i
];
891 if (fdx
->handleCount
> 0 &&
893 yaffsfs_inode
[fdx
->inodeId
].iObj
896 sharedReadAllowed
= 0;
897 if (!fdx
->shareWrite
)
898 sharedWriteAllowed
= 0;
906 if ((!sharedReadAllowed
&& readRequested
) ||
907 (!shareRead
&& alreadyReading
) ||
908 (!sharedWriteAllowed
&& writeRequested
) ||
909 (!shareWrite
&& alreadyWriting
)) {
911 yaffsfs_SetError(-EBUSY
);
918 /* If we could not open an existing object, then let's see if
919 * the directory exists. If not, error.
921 if (!obj
&& !errorReported
) {
922 dir
= yaffsfs_FindDirectory(NULL
, path
, &name
, 0,
924 if (!dir
&& notDir
) {
925 yaffsfs_SetError(-ENOTDIR
);
928 yaffsfs_SetError(-ELOOP
);
931 yaffsfs_SetError(-ENOENT
);
936 if (!obj
&& dir
&& !errorReported
&& (oflag
& O_CREAT
)) {
937 /* Let's see if we can create this file */
938 if (dir
->my_dev
->read_only
) {
939 yaffsfs_SetError(-EROFS
);
941 } else if (yaffsfs_TooManyObjects(dir
->my_dev
)) {
942 yaffsfs_SetError(-ENFILE
);
945 obj
= yaffs_create_file(dir
, name
, mode
, 0, 0);
947 if (!obj
&& !errorReported
) {
948 yaffsfs_SetError(-ENOSPC
);
953 if (!obj
&& dir
&& !errorReported
&& !(oflag
& O_CREAT
)) {
954 yaffsfs_SetError(-ENOENT
);
958 if (obj
&& !openDenied
) {
959 int inodeId
= yaffsfs_GetInodeIdForObject(obj
);
963 * Todo: Fix any problem if inodes run out,
964 * That can't happen if the number of inode
965 * items >= number of handles.
969 fd
->inodeId
= inodeId
;
970 fd
->reading
= readRequested
;
971 fd
->writing
= writeRequested
;
972 fd
->append
= (oflag
& O_APPEND
) ? 1 : 0;
974 fd
->shareRead
= shareRead
;
975 fd
->shareWrite
= shareWrite
;
977 /* Hook inode to object */
978 obj
->my_inode
= (void *)&yaffsfs_inode
[inodeId
];
980 if ((oflag
& O_TRUNC
) && fd
->writing
)
981 yaffs_resize_file(obj
, 0);
983 yaffsfs_PutHandle(handle
);
985 yaffsfs_SetError(0); /* Problem */
995 int yaffs_open(const YCHAR
*path
, int oflag
, int mode
)
997 return yaffs_open_sharing(path
, oflag
, mode
,
998 YAFFS_SHARE_READ
| YAFFS_SHARE_WRITE
);
1001 int yaffs_Dofsync(int handle
, int datasync
)
1004 struct yaffs_obj
*obj
;
1008 obj
= yaffsfs_HandleToObject(handle
);
1011 yaffsfs_SetError(-EBADF
);
1012 else if (obj
->my_dev
->read_only
)
1013 yaffsfs_SetError(-EROFS
);
1015 yaffs_flush_file(obj
, 1, datasync
);
1024 int yaffs_fsync(int handle
)
1026 return yaffs_Dofsync(handle
, 0);
1029 int yaffs_flush(int handle
)
1031 return yaffs_fsync(handle
);
1034 int yaffs_fdatasync(int handle
)
1036 return yaffs_Dofsync(handle
, 1);
1039 int yaffs_close(int handle
)
1041 struct yaffsfs_Handle
*h
= NULL
;
1042 struct yaffs_obj
*obj
= NULL
;
1047 h
= yaffsfs_HandleToPointer(handle
);
1048 obj
= yaffsfs_HandleToObject(handle
);
1051 yaffsfs_SetError(-EBADF
);
1054 yaffs_flush_file(obj
, 1, 0);
1055 yaffsfs_PutHandle(handle
);
1064 int yaffsfs_do_read(int handle
, void *vbuf
, unsigned int nbyte
,
1065 int isPread
, loff_t offset
)
1067 struct yaffsfs_FileDes
*fd
= NULL
;
1068 struct yaffs_obj
*obj
= NULL
;
1070 loff_t startPos
= 0;
1076 u8
*buf
= (u8
*) vbuf
;
1079 yaffsfs_SetError(-EFAULT
);
1084 fd
= yaffsfs_HandleToFileDes(handle
);
1085 obj
= yaffsfs_HandleToObject(handle
);
1089 yaffsfs_SetError(-EBADF
);
1091 } else if (!fd
->reading
) {
1092 /* Not a reading handle */
1093 yaffsfs_SetError(-EINVAL
);
1095 } else if (nbyte
> YAFFS_MAX_FILE_SIZE
) {
1096 yaffsfs_SetError(-EINVAL
);
1102 startPos
= fd
->position
;
1106 if (yaffs_get_obj_length(obj
) > pos
)
1107 maxRead
= yaffs_get_obj_length(obj
) - pos
;
1111 if (nbyte
> maxRead
)
1114 yaffsfs_GetHandle(handle
);
1116 endPos
= pos
+ nbyte
;
1118 if (pos
< 0 || pos
> YAFFS_MAX_FILE_SIZE
||
1119 nbyte
> YAFFS_MAX_FILE_SIZE
||
1120 endPos
< 0 || endPos
> YAFFS_MAX_FILE_SIZE
) {
1126 nToRead
= YAFFSFS_RW_SIZE
-
1127 (pos
& (YAFFSFS_RW_SIZE
- 1));
1128 if (nToRead
> nbyte
)
1132 * Need to reverify object in case the device was
1133 * unmounted in another thread.
1135 obj
= yaffsfs_HandleToObject(handle
);
1139 nRead
= yaffs_file_rd(obj
, buf
, pos
, nToRead
);
1147 if (nRead
== nToRead
)
1150 nbyte
= 0; /* no more to read */
1159 yaffsfs_PutHandle(handle
);
1163 fd
->position
= startPos
+ totalRead
;
1165 yaffsfs_SetError(-EINVAL
);
1172 return (totalRead
>= 0) ? totalRead
: -1;
1176 int yaffs_read(int handle
, void *buf
, unsigned int nbyte
)
1178 return yaffsfs_do_read(handle
, buf
, nbyte
, 0, 0);
1181 int yaffs_pread(int handle
, void *buf
, unsigned int nbyte
, loff_t offset
)
1183 return yaffsfs_do_read(handle
, buf
, nbyte
, 1, offset
);
1186 int yaffsfs_do_write(int handle
, const void *vbuf
, unsigned int nbyte
,
1187 int isPwrite
, loff_t offset
)
1189 struct yaffsfs_FileDes
*fd
= NULL
;
1190 struct yaffs_obj
*obj
= NULL
;
1192 loff_t startPos
= 0;
1195 int totalWritten
= 0;
1196 int write_trhrough
= 0;
1198 const u8
*buf
= (const u8
*)vbuf
;
1201 yaffsfs_SetError(-EFAULT
);
1206 fd
= yaffsfs_HandleToFileDes(handle
);
1207 obj
= yaffsfs_HandleToObject(handle
);
1211 yaffsfs_SetError(-EBADF
);
1213 } else if (!fd
->writing
) {
1214 yaffsfs_SetError(-EINVAL
);
1216 } else if (obj
->my_dev
->read_only
) {
1217 yaffsfs_SetError(-EROFS
);
1221 startPos
= yaffs_get_obj_length(obj
);
1225 startPos
= fd
->position
;
1227 yaffsfs_GetHandle(handle
);
1229 endPos
= pos
+ nbyte
;
1231 if (pos
< 0 || pos
> YAFFS_MAX_FILE_SIZE
||
1232 nbyte
> YAFFS_MAX_FILE_SIZE
||
1233 endPos
< 0 || endPos
> YAFFS_MAX_FILE_SIZE
) {
1240 nToWrite
= YAFFSFS_RW_SIZE
-
1241 (pos
& (YAFFSFS_RW_SIZE
- 1));
1242 if (nToWrite
> nbyte
)
1246 * Need to reverify object in case the device was
1247 * remounted or unmounted in another thread.
1249 obj
= yaffsfs_HandleToObject(handle
);
1250 if (!obj
|| obj
->my_dev
->read_only
)
1254 yaffs_wr_file(obj
, buf
, pos
, nToWrite
,
1257 totalWritten
+= nWritten
;
1262 if (nWritten
== nToWrite
)
1267 if (nWritten
< 1 && totalWritten
< 1) {
1268 yaffsfs_SetError(-ENOSPC
);
1278 yaffsfs_PutHandle(handle
);
1281 if (totalWritten
> 0)
1282 fd
->position
= startPos
+ totalWritten
;
1284 yaffsfs_SetError(-EINVAL
);
1290 return (totalWritten
>= 0) ? totalWritten
: -1;
1293 int yaffs_write(int fd
, const void *buf
, unsigned int nbyte
)
1295 return yaffsfs_do_write(fd
, buf
, nbyte
, 0, 0);
1298 int yaffs_pwrite(int fd
, const void *buf
, unsigned int nbyte
, loff_t offset
)
1300 return yaffsfs_do_write(fd
, buf
, nbyte
, 1, offset
);
1303 int yaffs_truncate(const YCHAR
*path
, loff_t new_size
)
1305 struct yaffs_obj
*obj
= NULL
;
1306 struct yaffs_obj
*dir
= NULL
;
1307 int result
= YAFFS_FAIL
;
1312 yaffsfs_SetError(-EFAULT
);
1316 if (yaffsfs_CheckPath(path
) < 0) {
1317 yaffsfs_SetError(-ENAMETOOLONG
);
1323 obj
= yaffsfs_FindObject(NULL
, path
, 0, 1, &dir
, ¬Dir
, &loop
);
1324 obj
= yaffsfs_FollowLink(obj
, 0, &loop
);
1327 yaffsfs_SetError(-ENOTDIR
);
1329 yaffsfs_SetError(-ELOOP
);
1330 else if (!dir
|| !obj
)
1331 yaffsfs_SetError(-ENOENT
);
1332 else if (obj
->my_dev
->read_only
)
1333 yaffsfs_SetError(-EROFS
);
1334 else if (obj
->variant_type
!= YAFFS_OBJECT_TYPE_FILE
)
1335 yaffsfs_SetError(-EISDIR
);
1336 else if (obj
->my_dev
->read_only
)
1337 yaffsfs_SetError(-EROFS
);
1338 else if (new_size
< 0 || new_size
> YAFFS_MAX_FILE_SIZE
)
1339 yaffsfs_SetError(-EINVAL
);
1341 result
= yaffs_resize_file(obj
, new_size
);
1345 return (result
) ? 0 : -1;
1348 int yaffs_ftruncate(int handle
, loff_t new_size
)
1350 struct yaffsfs_FileDes
*fd
= NULL
;
1351 struct yaffs_obj
*obj
= NULL
;
1355 fd
= yaffsfs_HandleToFileDes(handle
);
1356 obj
= yaffsfs_HandleToObject(handle
);
1360 yaffsfs_SetError(-EBADF
);
1361 else if (!fd
->writing
)
1362 yaffsfs_SetError(-EINVAL
);
1363 else if (obj
->my_dev
->read_only
)
1364 yaffsfs_SetError(-EROFS
);
1365 else if (new_size
< 0 || new_size
> YAFFS_MAX_FILE_SIZE
)
1366 yaffsfs_SetError(-EINVAL
);
1368 /* resize the file */
1369 result
= yaffs_resize_file(obj
, new_size
);
1372 return (result
) ? 0 : -1;
1376 loff_t
yaffs_lseek(int handle
, loff_t offset
, int whence
)
1378 struct yaffsfs_FileDes
*fd
= NULL
;
1379 struct yaffs_obj
*obj
= NULL
;
1384 fd
= yaffsfs_HandleToFileDes(handle
);
1385 obj
= yaffsfs_HandleToObject(handle
);
1388 yaffsfs_SetError(-EBADF
);
1389 else if (offset
> YAFFS_MAX_FILE_SIZE
)
1390 yaffsfs_SetError(-EINVAL
);
1392 if (whence
== SEEK_SET
) {
1395 } else if (whence
== SEEK_CUR
) {
1396 if ((fd
->position
+ offset
) >= 0)
1397 pos
= (fd
->position
+ offset
);
1398 } else if (whence
== SEEK_END
) {
1399 fSize
= yaffs_get_obj_length(obj
);
1400 if (fSize
>= 0 && (fSize
+ offset
) >= 0)
1401 pos
= fSize
+ offset
;
1404 if (pos
>= 0 && pos
<= YAFFS_MAX_FILE_SIZE
)
1407 yaffsfs_SetError(-EINVAL
);
1417 int yaffsfs_DoUnlink(const YCHAR
*path
, int isDirectory
)
1419 struct yaffs_obj
*dir
= NULL
;
1420 struct yaffs_obj
*obj
= NULL
;
1422 int result
= YAFFS_FAIL
;
1427 yaffsfs_SetError(-EFAULT
);
1431 if (yaffsfs_CheckPath(path
) < 0) {
1432 yaffsfs_SetError(-ENAMETOOLONG
);
1438 obj
= yaffsfs_FindObject(NULL
, path
, 0, 0, NULL
, NULL
, NULL
);
1439 dir
= yaffsfs_FindDirectory(NULL
, path
, &name
, 0, ¬Dir
, &loop
);
1442 yaffsfs_SetError(-ENOTDIR
);
1444 yaffsfs_SetError(-ELOOP
);
1446 yaffsfs_SetError(-ENOENT
);
1447 else if (yaffs_strncmp(name
, _Y("."), 2) == 0)
1448 yaffsfs_SetError(-EINVAL
);
1450 yaffsfs_SetError(-ENOENT
);
1451 else if (obj
->my_dev
->read_only
)
1452 yaffsfs_SetError(-EROFS
);
1453 else if (!isDirectory
&&
1454 obj
->variant_type
== YAFFS_OBJECT_TYPE_DIRECTORY
)
1455 yaffsfs_SetError(-EISDIR
);
1456 else if (isDirectory
&&
1457 obj
->variant_type
!= YAFFS_OBJECT_TYPE_DIRECTORY
)
1458 yaffsfs_SetError(-ENOTDIR
);
1459 else if (isDirectory
&& obj
== obj
->my_dev
->root_dir
)
1460 yaffsfs_SetError(-EBUSY
); /* Can't rmdir a root */
1462 result
= yaffs_unlinker(dir
, name
);
1464 if (result
== YAFFS_FAIL
&& isDirectory
)
1465 yaffsfs_SetError(-ENOTEMPTY
);
1470 return (result
== YAFFS_FAIL
) ? -1 : 0;
1473 int yaffs_unlink(const YCHAR
*path
)
1475 return yaffsfs_DoUnlink(path
, 0);
1478 int yaffs_rename(const YCHAR
*oldPath
, const YCHAR
*newPath
)
1480 struct yaffs_obj
*olddir
= NULL
;
1481 struct yaffs_obj
*newdir
= NULL
;
1482 struct yaffs_obj
*obj
= NULL
;
1483 struct yaffs_obj
*newobj
= NULL
;
1486 int result
= YAFFS_FAIL
;
1487 int rename_allowed
= 1;
1493 YCHAR
*alt_newpath
= NULL
;
1495 if (!oldPath
|| !newPath
) {
1496 yaffsfs_SetError(-EFAULT
);
1500 if (yaffsfs_CheckPath(oldPath
) < 0 || yaffsfs_CheckPath(newPath
) < 0) {
1501 yaffsfs_SetError(-ENAMETOOLONG
);
1505 if (yaffsfs_alt_dir_path(newPath
, &alt_newpath
) < 0) {
1506 yaffsfs_SetError(-ENOMEM
);
1510 newPath
= alt_newpath
;
1514 olddir
= yaffsfs_FindDirectory(NULL
, oldPath
, &oldname
, 0,
1515 ¬OldDir
, &oldLoop
);
1516 newdir
= yaffsfs_FindDirectory(NULL
, newPath
, &newname
, 0,
1517 ¬NewDir
, &newLoop
);
1518 obj
= yaffsfs_FindObject(NULL
, oldPath
, 0, 0, NULL
, NULL
, NULL
);
1519 newobj
= yaffsfs_FindObject(NULL
, newPath
, 0, 0, NULL
, NULL
, NULL
);
1521 /* If the object being renamed is a directory and the
1522 * path ended with a "/" then the olddir == obj.
1523 * We pass through NULL for the old name to tell the lower layers
1524 * to use olddir as the object.
1530 if ((!olddir
&& notOldDir
) || (!newdir
&& notNewDir
)) {
1531 yaffsfs_SetError(-ENOTDIR
);
1533 } else if (oldLoop
|| newLoop
) {
1534 yaffsfs_SetError(-ELOOP
);
1536 } else if (olddir
&& oldname
&&
1537 yaffs_strncmp(oldname
, _Y("."), 2) == 0) {
1538 yaffsfs_SetError(-EINVAL
);
1540 } else if (!olddir
|| !newdir
|| !obj
) {
1541 yaffsfs_SetError(-ENOENT
);
1543 } else if (obj
->my_dev
->read_only
) {
1544 yaffsfs_SetError(-EROFS
);
1546 } else if (yaffs_is_non_empty_dir(newobj
)) {
1547 yaffsfs_SetError(-ENOTEMPTY
);
1549 } else if (olddir
->my_dev
!= newdir
->my_dev
) {
1550 /* Rename must be on same device */
1551 yaffsfs_SetError(-EXDEV
);
1553 } else if (obj
&& obj
->variant_type
== YAFFS_OBJECT_TYPE_DIRECTORY
) {
1555 * It is a directory, check that it is not being renamed to
1556 * being its own decendent.
1557 * Do this by tracing from the new directory back to the root,
1561 struct yaffs_obj
*xx
= newdir
;
1563 while (rename_allowed
&& xx
) {
1568 if (!rename_allowed
)
1569 yaffsfs_SetError(-EINVAL
);
1573 result
= yaffs_rename_obj(olddir
, oldname
, newdir
, newname
);
1579 return (result
== YAFFS_FAIL
) ? -1 : 0;
1582 static int yaffsfs_DoStat(struct yaffs_obj
*obj
, struct yaffs_stat
*buf
)
1586 obj
= yaffs_get_equivalent_obj(obj
);
1589 buf
->st_dev
= (int)obj
->my_dev
->os_context
;
1590 buf
->st_ino
= obj
->obj_id
;
1591 buf
->st_mode
= obj
->yst_mode
& ~S_IFMT
;
1593 if (obj
->variant_type
== YAFFS_OBJECT_TYPE_DIRECTORY
)
1594 buf
->st_mode
|= S_IFDIR
;
1595 else if (obj
->variant_type
== YAFFS_OBJECT_TYPE_SYMLINK
)
1596 buf
->st_mode
|= S_IFLNK
;
1597 else if (obj
->variant_type
== YAFFS_OBJECT_TYPE_FILE
)
1598 buf
->st_mode
|= S_IFREG
;
1600 buf
->st_nlink
= yaffs_get_obj_link_count(obj
);
1603 buf
->st_rdev
= obj
->yst_rdev
;
1604 buf
->st_size
= yaffs_get_obj_length(obj
);
1605 buf
->st_blksize
= obj
->my_dev
->data_bytes_per_chunk
;
1606 buf
->st_blocks
= (buf
->st_size
+ buf
->st_blksize
- 1) /
1608 #if CONFIG_YAFFS_WINCE
1609 buf
->yst_wince_atime
[0] = obj
->win_atime
[0];
1610 buf
->yst_wince_atime
[1] = obj
->win_atime
[1];
1611 buf
->yst_wince_ctime
[0] = obj
->win_ctime
[0];
1612 buf
->yst_wince_ctime
[1] = obj
->win_ctime
[1];
1613 buf
->yst_wince_mtime
[0] = obj
->win_mtime
[0];
1614 buf
->yst_wince_mtime
[1] = obj
->win_mtime
[1];
1616 buf
->yst_atime
= obj
->yst_atime
;
1617 buf
->yst_ctime
= obj
->yst_ctime
;
1618 buf
->yst_mtime
= obj
->yst_mtime
;
1625 static int yaffsfs_DoStatOrLStat(const YCHAR
*path
,
1626 struct yaffs_stat
*buf
, int doLStat
)
1628 struct yaffs_obj
*obj
= NULL
;
1629 struct yaffs_obj
*dir
= NULL
;
1634 if (!path
|| !buf
) {
1635 yaffsfs_SetError(-EFAULT
);
1639 if (yaffsfs_CheckPath(path
) < 0) {
1640 yaffsfs_SetError(-ENAMETOOLONG
);
1646 obj
= yaffsfs_FindObject(NULL
, path
, 0, 1, &dir
, ¬Dir
, &loop
);
1648 if (!doLStat
&& obj
)
1649 obj
= yaffsfs_FollowLink(obj
, 0, &loop
);
1652 yaffsfs_SetError(-ENOTDIR
);
1654 yaffsfs_SetError(-ELOOP
);
1655 else if (!dir
|| !obj
)
1656 yaffsfs_SetError(-ENOENT
);
1658 retVal
= yaffsfs_DoStat(obj
, buf
);
1666 int yaffs_stat(const YCHAR
*path
, struct yaffs_stat
*buf
)
1668 return yaffsfs_DoStatOrLStat(path
, buf
, 0);
1671 int yaffs_lstat(const YCHAR
*path
, struct yaffs_stat
*buf
)
1673 return yaffsfs_DoStatOrLStat(path
, buf
, 1);
1676 int yaffs_fstat(int fd
, struct yaffs_stat
*buf
)
1678 struct yaffs_obj
*obj
;
1683 yaffsfs_SetError(-EFAULT
);
1688 obj
= yaffsfs_HandleToObject(fd
);
1691 retVal
= yaffsfs_DoStat(obj
, buf
);
1694 yaffsfs_SetError(-EBADF
);
1701 static int yaffsfs_DoUtime(struct yaffs_obj
*obj
,
1702 const struct yaffs_utimbuf
*buf
)
1707 struct yaffs_utimbuf local
;
1709 obj
= yaffs_get_equivalent_obj(obj
);
1711 if (obj
&& obj
->my_dev
->read_only
) {
1712 yaffsfs_SetError(-EROFS
);
1717 local
.actime
= Y_CURRENT_TIME
;
1718 local
.modtime
= local
.actime
;
1723 obj
->yst_atime
= buf
->actime
;
1724 obj
->yst_mtime
= buf
->modtime
;
1726 result
= yaffs_flush_file(obj
, 0, 0);
1727 retVal
= result
== YAFFS_OK
? 0 : -1;
1733 int yaffs_utime(const YCHAR
*path
, const struct yaffs_utimbuf
*buf
)
1735 struct yaffs_obj
*obj
= NULL
;
1736 struct yaffs_obj
*dir
= NULL
;
1742 yaffsfs_SetError(-EFAULT
);
1746 if (yaffsfs_CheckPath(path
) < 0) {
1747 yaffsfs_SetError(-ENAMETOOLONG
);
1753 obj
= yaffsfs_FindObject(NULL
, path
, 0, 1, &dir
, ¬Dir
, &loop
);
1756 yaffsfs_SetError(-ENOTDIR
);
1758 yaffsfs_SetError(-ELOOP
);
1759 else if (!dir
|| !obj
)
1760 yaffsfs_SetError(-ENOENT
);
1762 retVal
= yaffsfs_DoUtime(obj
, buf
);
1770 int yaffs_futime(int fd
, const struct yaffs_utimbuf
*buf
)
1772 struct yaffs_obj
*obj
;
1777 obj
= yaffsfs_HandleToObject(fd
);
1780 retVal
= yaffsfs_DoUtime(obj
, buf
);
1783 yaffsfs_SetError(-EBADF
);
1790 #ifndef CONFIG_YAFFS_WINCE
1791 /* xattrib functions */
1793 static int yaffs_do_setxattr(const YCHAR
*path
, const char *name
,
1794 const void *data
, int size
, int flags
, int follow
)
1796 struct yaffs_obj
*obj
;
1797 struct yaffs_obj
*dir
;
1803 if (!path
|| !name
|| !data
) {
1804 yaffsfs_SetError(-EFAULT
);
1808 if (yaffsfs_CheckPath(path
) < 0) {
1809 yaffsfs_SetError(-ENAMETOOLONG
);
1815 obj
= yaffsfs_FindObject(NULL
, path
, 0, 1, &dir
, ¬Dir
, &loop
);
1818 obj
= yaffsfs_FollowLink(obj
, 0, &loop
);
1821 yaffsfs_SetError(-ENOTDIR
);
1823 yaffsfs_SetError(-ELOOP
);
1824 else if (!dir
|| !obj
)
1825 yaffsfs_SetError(-ENOENT
);
1827 retVal
= yaffs_set_xattrib(obj
, name
, data
, size
, flags
);
1829 yaffsfs_SetError(retVal
);
1840 int yaffs_setxattr(const YCHAR
*path
, const char *name
,
1841 const void *data
, int size
, int flags
)
1843 return yaffs_do_setxattr(path
, name
, data
, size
, flags
, 1);
1846 int yaffs_lsetxattr(const YCHAR
*path
, const char *name
,
1847 const void *data
, int size
, int flags
)
1849 return yaffs_do_setxattr(path
, name
, data
, size
, flags
, 0);
1852 int yaffs_fsetxattr(int fd
, const char *name
,
1853 const void *data
, int size
, int flags
)
1855 struct yaffs_obj
*obj
;
1859 if (!name
|| !data
) {
1860 yaffsfs_SetError(-EFAULT
);
1865 obj
= yaffsfs_HandleToObject(fd
);
1868 yaffsfs_SetError(-EBADF
);
1870 retVal
= yaffs_set_xattrib(obj
, name
, data
, size
, flags
);
1872 yaffsfs_SetError(retVal
);
1882 static int yaffs_do_getxattr(const YCHAR
*path
, const char *name
,
1883 void *data
, int size
, int follow
)
1885 struct yaffs_obj
*obj
;
1886 struct yaffs_obj
*dir
;
1891 if (!path
|| !name
|| !data
) {
1892 yaffsfs_SetError(-EFAULT
);
1896 if (yaffsfs_CheckPath(path
) < 0) {
1897 yaffsfs_SetError(-ENAMETOOLONG
);
1903 obj
= yaffsfs_FindObject(NULL
, path
, 0, 1, &dir
, ¬Dir
, &loop
);
1906 obj
= yaffsfs_FollowLink(obj
, 0, &loop
);
1909 yaffsfs_SetError(-ENOTDIR
);
1911 yaffsfs_SetError(-ELOOP
);
1912 else if (!dir
|| !obj
)
1913 yaffsfs_SetError(-ENOENT
);
1915 retVal
= yaffs_get_xattrib(obj
, name
, data
, size
);
1917 yaffsfs_SetError(retVal
);
1927 int yaffs_getxattr(const YCHAR
*path
, const char *name
, void *data
, int size
)
1929 return yaffs_do_getxattr(path
, name
, data
, size
, 1);
1932 int yaffs_lgetxattr(const YCHAR
*path
, const char *name
, void *data
, int size
)
1934 return yaffs_do_getxattr(path
, name
, data
, size
, 0);
1937 int yaffs_fgetxattr(int fd
, const char *name
, void *data
, int size
)
1939 struct yaffs_obj
*obj
;
1943 if (!name
|| !data
) {
1944 yaffsfs_SetError(-EFAULT
);
1949 obj
= yaffsfs_HandleToObject(fd
);
1952 retVal
= yaffs_get_xattrib(obj
, name
, data
, size
);
1954 yaffsfs_SetError(retVal
);
1959 yaffsfs_SetError(-EBADF
);
1966 static int yaffs_do_listxattr(const YCHAR
*path
, char *data
,
1967 int size
, int follow
)
1969 struct yaffs_obj
*obj
= NULL
;
1970 struct yaffs_obj
*dir
= NULL
;
1975 if (!path
|| !data
) {
1976 yaffsfs_SetError(-EFAULT
);
1980 if (yaffsfs_CheckPath(path
) < 0) {
1981 yaffsfs_SetError(-ENAMETOOLONG
);
1987 obj
= yaffsfs_FindObject(NULL
, path
, 0, 1, &dir
, ¬Dir
, &loop
);
1990 obj
= yaffsfs_FollowLink(obj
, 0, &loop
);
1993 yaffsfs_SetError(-ENOTDIR
);
1995 yaffsfs_SetError(-ELOOP
);
1996 else if (!dir
|| !obj
)
1997 yaffsfs_SetError(-ENOENT
);
1999 retVal
= yaffs_list_xattrib(obj
, data
, size
);
2001 yaffsfs_SetError(retVal
);
2012 int yaffs_listxattr(const YCHAR
*path
, char *data
, int size
)
2014 return yaffs_do_listxattr(path
, data
, size
, 1);
2017 int yaffs_llistxattr(const YCHAR
*path
, char *data
, int size
)
2019 return yaffs_do_listxattr(path
, data
, size
, 0);
2022 int yaffs_flistxattr(int fd
, char *data
, int size
)
2024 struct yaffs_obj
*obj
;
2029 yaffsfs_SetError(-EFAULT
);
2034 obj
= yaffsfs_HandleToObject(fd
);
2037 retVal
= yaffs_list_xattrib(obj
, data
, size
);
2039 yaffsfs_SetError(retVal
);
2044 yaffsfs_SetError(-EBADF
);
2051 static int yaffs_do_removexattr(const YCHAR
*path
, const char *name
,
2054 struct yaffs_obj
*obj
= NULL
;
2055 struct yaffs_obj
*dir
= NULL
;
2060 if (!path
|| !name
) {
2061 yaffsfs_SetError(-EFAULT
);
2065 if (yaffsfs_CheckPath(path
) < 0) {
2066 yaffsfs_SetError(-ENAMETOOLONG
);
2072 obj
= yaffsfs_FindObject(NULL
, path
, 0, 1, &dir
, ¬Dir
, &loop
);
2075 obj
= yaffsfs_FollowLink(obj
, 0, &loop
);
2078 yaffsfs_SetError(-ENOTDIR
);
2080 yaffsfs_SetError(-ELOOP
);
2081 else if (!dir
|| !obj
)
2082 yaffsfs_SetError(-ENOENT
);
2084 retVal
= yaffs_remove_xattrib(obj
, name
);
2086 yaffsfs_SetError(retVal
);
2097 int yaffs_removexattr(const YCHAR
*path
, const char *name
)
2099 return yaffs_do_removexattr(path
, name
, 1);
2102 int yaffs_lremovexattr(const YCHAR
*path
, const char *name
)
2104 return yaffs_do_removexattr(path
, name
, 0);
2107 int yaffs_fremovexattr(int fd
, const char *name
)
2109 struct yaffs_obj
*obj
;
2114 yaffsfs_SetError(-EFAULT
);
2119 obj
= yaffsfs_HandleToObject(fd
);
2122 retVal
= yaffs_remove_xattrib(obj
, name
);
2124 yaffsfs_SetError(retVal
);
2129 yaffsfs_SetError(-EBADF
);
2137 #ifdef CONFIG_YAFFS_WINCE
2138 int yaffs_get_wince_times(int fd
, unsigned *wctime
,
2139 unsigned *watime
, unsigned *wmtime
)
2141 struct yaffs_obj
*obj
;
2146 obj
= yaffsfs_HandleToObject(fd
);
2151 wctime
[0] = obj
->win_ctime
[0];
2152 wctime
[1] = obj
->win_ctime
[1];
2155 watime
[0] = obj
->win_atime
[0];
2156 watime
[1] = obj
->win_atime
[1];
2159 wmtime
[0] = obj
->win_mtime
[0];
2160 wmtime
[1] = obj
->win_mtime
[1];
2166 yaffsfs_SetError(-EBADF
);
2173 int yaffs_set_wince_times(int fd
,
2174 const unsigned *wctime
,
2175 const unsigned *watime
, const unsigned *wmtime
)
2177 struct yaffs_obj
*obj
;
2182 obj
= yaffsfs_HandleToObject(fd
);
2187 obj
->win_ctime
[0] = wctime
[0];
2188 obj
->win_ctime
[1] = wctime
[1];
2191 obj
->win_atime
[0] = watime
[0];
2192 obj
->win_atime
[1] = watime
[1];
2195 obj
->win_mtime
[0] = wmtime
[0];
2196 obj
->win_mtime
[1] = wmtime
[1];
2200 result
= yaffs_flush_file(obj
, 0, 0);
2204 yaffsfs_SetError(-EBADF
);
2213 static int yaffsfs_DoChMod(struct yaffs_obj
*obj
, mode_t mode
)
2218 obj
= yaffs_get_equivalent_obj(obj
);
2221 obj
->yst_mode
= mode
;
2223 result
= yaffs_flush_file(obj
, 0, 0);
2226 return result
== YAFFS_OK
? 0 : -1;
2229 int yaffs_access(const YCHAR
*path
, int amode
)
2231 struct yaffs_obj
*obj
= NULL
;
2232 struct yaffs_obj
*dir
= NULL
;
2238 yaffsfs_SetError(-EFAULT
);
2242 if (yaffsfs_CheckPath(path
) < 0) {
2243 yaffsfs_SetError(-ENAMETOOLONG
);
2247 if (amode
& ~(R_OK
| W_OK
| X_OK
)) {
2248 yaffsfs_SetError(-EINVAL
);
2254 obj
= yaffsfs_FindObject(NULL
, path
, 0, 1, &dir
, ¬Dir
, &loop
);
2255 obj
= yaffsfs_FollowLink(obj
, 0, &loop
);
2258 yaffsfs_SetError(-ENOTDIR
);
2260 yaffsfs_SetError(-ELOOP
);
2261 else if (!dir
|| !obj
)
2262 yaffsfs_SetError(-ENOENT
);
2263 else if ((amode
& W_OK
) && obj
->my_dev
->read_only
)
2264 yaffsfs_SetError(-EROFS
);
2268 if ((amode
& R_OK
) && !(obj
->yst_mode
& S_IREAD
))
2270 if ((amode
& W_OK
) && !(obj
->yst_mode
& S_IWRITE
))
2272 if ((amode
& X_OK
) && !(obj
->yst_mode
& S_IEXEC
))
2276 yaffsfs_SetError(-EACCES
);
2287 int yaffs_chmod(const YCHAR
*path
, mode_t mode
)
2289 struct yaffs_obj
*obj
= NULL
;
2290 struct yaffs_obj
*dir
= NULL
;
2296 yaffsfs_SetError(-EFAULT
);
2300 if (yaffsfs_CheckPath(path
) < 0) {
2301 yaffsfs_SetError(-ENAMETOOLONG
);
2305 if (mode
& ~(0777)) {
2306 yaffsfs_SetError(-EINVAL
);
2312 obj
= yaffsfs_FindObject(NULL
, path
, 0, 1, &dir
, ¬Dir
, &loop
);
2313 obj
= yaffsfs_FollowLink(obj
, 0, &loop
);
2316 yaffsfs_SetError(-ENOTDIR
);
2318 yaffsfs_SetError(-ELOOP
);
2319 else if (!dir
|| !obj
)
2320 yaffsfs_SetError(-ENOENT
);
2321 else if (obj
->my_dev
->read_only
)
2322 yaffsfs_SetError(-EROFS
);
2324 retVal
= yaffsfs_DoChMod(obj
, mode
);
2332 int yaffs_fchmod(int fd
, mode_t mode
)
2334 struct yaffs_obj
*obj
;
2337 if (mode
& ~(0777)) {
2338 yaffsfs_SetError(-EINVAL
);
2343 obj
= yaffsfs_HandleToObject(fd
);
2346 yaffsfs_SetError(-EBADF
);
2347 else if (obj
->my_dev
->read_only
)
2348 yaffsfs_SetError(-EROFS
);
2350 retVal
= yaffsfs_DoChMod(obj
, mode
);
2357 int yaffs_mkdir(const YCHAR
*path
, mode_t mode
)
2359 struct yaffs_obj
*parent
= NULL
;
2360 struct yaffs_obj
*dir
= NULL
;
2362 YCHAR
*alt_path
= NULL
;
2368 yaffsfs_SetError(-EFAULT
);
2372 if (yaffsfs_CheckPath(path
) < 0) {
2373 yaffsfs_SetError(-ENAMETOOLONG
);
2377 if (yaffsfs_alt_dir_path(path
, &alt_path
) < 0) {
2378 yaffsfs_SetError(-ENOMEM
);
2385 parent
= yaffsfs_FindDirectory(NULL
, path
, &name
, 0, ¬Dir
, &loop
);
2386 if (!parent
&& notDir
)
2387 yaffsfs_SetError(-ENOTDIR
);
2389 yaffsfs_SetError(-ELOOP
);
2391 yaffsfs_SetError(-ENOENT
);
2392 else if (yaffsfs_TooManyObjects(parent
->my_dev
))
2393 yaffsfs_SetError(-ENFILE
);
2394 else if (yaffs_strnlen(name
, 5) == 0) {
2395 /* Trying to make the root itself */
2396 yaffsfs_SetError(-EEXIST
);
2397 } else if (parent
->my_dev
->read_only
)
2398 yaffsfs_SetError(-EROFS
);
2400 dir
= yaffs_create_dir(parent
, name
, mode
, 0, 0);
2403 else if (yaffs_find_by_name(parent
, name
))
2404 yaffsfs_SetError(-EEXIST
); /* name exists */
2406 yaffsfs_SetError(-ENOSPC
); /* assume no space */
2416 int yaffs_rmdir(const YCHAR
*path
)
2422 yaffsfs_SetError(-EFAULT
);
2426 if (yaffsfs_CheckPath(path
) < 0) {
2427 yaffsfs_SetError(-ENAMETOOLONG
);
2431 if (yaffsfs_alt_dir_path(path
, &alt_path
) < 0) {
2432 yaffsfs_SetError(-ENOMEM
);
2437 result
= yaffsfs_DoUnlink(path
, 1);
2444 void *yaffs_getdev(const YCHAR
*path
)
2446 struct yaffs_dev
*dev
= NULL
;
2448 dev
= yaffsfs_FindDevice(path
, &dummy
);
2452 int yaffs_mount_common(const YCHAR
*path
, int read_only
, int skip_checkpt
)
2455 int result
= YAFFS_FAIL
;
2456 struct yaffs_dev
*dev
= NULL
;
2459 yaffsfs_SetError(-EFAULT
);
2463 yaffs_trace(YAFFS_TRACE_MOUNT
, "yaffs: Mounting %s", path
);
2465 if (yaffsfs_CheckPath(path
) < 0) {
2466 yaffsfs_SetError(-ENAMETOOLONG
);
2472 yaffsfs_InitHandles();
2474 dev
= yaffsfs_FindMountPoint(path
);
2476 if (!dev
->is_mounted
) {
2477 dev
->read_only
= read_only
? 1 : 0;
2479 u8 skip
= dev
->param
.skip_checkpt_rd
;
2480 dev
->param
.skip_checkpt_rd
= 1;
2481 result
= yaffs_guts_initialise(dev
);
2482 dev
->param
.skip_checkpt_rd
= skip
;
2484 result
= yaffs_guts_initialise(dev
);
2487 if (result
== YAFFS_FAIL
)
2488 yaffsfs_SetError(-ENOMEM
);
2489 retVal
= result
? 0 : -1;
2492 yaffsfs_SetError(-EBUSY
);
2494 yaffsfs_SetError(-ENODEV
);
2501 int yaffs_mount2(const YCHAR
*path
, int readonly
)
2503 return yaffs_mount_common(path
, readonly
, 0);
2506 int yaffs_mount(const YCHAR
*path
)
2508 return yaffs_mount_common(path
, 0, 0);
2511 int yaffs_sync(const YCHAR
*path
)
2514 struct yaffs_dev
*dev
= NULL
;
2518 yaffsfs_SetError(-EFAULT
);
2522 if (yaffsfs_CheckPath(path
) < 0) {
2523 yaffsfs_SetError(-ENAMETOOLONG
);
2528 dev
= yaffsfs_FindDevice(path
, &dummy
);
2530 if (!dev
->is_mounted
)
2531 yaffsfs_SetError(-EINVAL
);
2532 else if (dev
->read_only
)
2533 yaffsfs_SetError(-EROFS
);
2536 yaffs_flush_whole_cache(dev
);
2537 yaffs_checkpoint_save(dev
);
2542 yaffsfs_SetError(-ENODEV
);
2548 static int yaffsfs_IsDevBusy(struct yaffs_dev
*dev
)
2551 struct yaffs_obj
*obj
;
2553 for (i
= 0; i
< YAFFSFS_N_HANDLES
; i
++) {
2554 obj
= yaffsfs_HandleToObject(i
);
2555 if (obj
&& obj
->my_dev
== dev
)
2561 int yaffs_remount(const YCHAR
*path
, int force
, int read_only
)
2564 struct yaffs_dev
*dev
= NULL
;
2567 yaffsfs_SetError(-EFAULT
);
2571 if (yaffsfs_CheckPath(path
) < 0) {
2572 yaffsfs_SetError(-ENAMETOOLONG
);
2577 dev
= yaffsfs_FindMountPoint(path
);
2579 if (dev
->is_mounted
) {
2580 yaffs_flush_whole_cache(dev
);
2582 if (force
|| !yaffsfs_IsDevBusy(dev
)) {
2584 yaffs_checkpoint_save(dev
);
2585 dev
->read_only
= read_only
? 1 : 0;
2588 yaffsfs_SetError(-EBUSY
);
2591 yaffsfs_SetError(-EINVAL
);
2594 yaffsfs_SetError(-ENODEV
);
2601 int yaffs_unmount2(const YCHAR
*path
, int force
)
2604 struct yaffs_dev
*dev
= NULL
;
2607 yaffsfs_SetError(-EFAULT
);
2611 if (yaffsfs_CheckPath(path
) < 0) {
2612 yaffsfs_SetError(-ENAMETOOLONG
);
2617 dev
= yaffsfs_FindMountPoint(path
);
2619 if (dev
->is_mounted
) {
2621 yaffs_flush_whole_cache(dev
);
2622 yaffs_checkpoint_save(dev
);
2623 inUse
= yaffsfs_IsDevBusy(dev
);
2624 if (!inUse
|| force
) {
2626 yaffsfs_BreakDeviceHandles(dev
);
2627 yaffs_deinitialise(dev
);
2631 yaffsfs_SetError(-EBUSY
);
2634 yaffsfs_SetError(-EINVAL
);
2637 yaffsfs_SetError(-ENODEV
);
2644 int yaffs_unmount(const YCHAR
*path
)
2646 return yaffs_unmount2(path
, 0);
2649 loff_t
yaffs_freespace(const YCHAR
*path
)
2652 struct yaffs_dev
*dev
= NULL
;
2656 yaffsfs_SetError(-EFAULT
);
2660 if (yaffsfs_CheckPath(path
) < 0) {
2661 yaffsfs_SetError(-ENAMETOOLONG
);
2666 dev
= yaffsfs_FindDevice(path
, &dummy
);
2667 if (dev
&& dev
->is_mounted
) {
2668 retVal
= yaffs_get_n_free_chunks(dev
);
2669 retVal
*= dev
->data_bytes_per_chunk
;
2672 yaffsfs_SetError(-EINVAL
);
2678 loff_t
yaffs_totalspace(const YCHAR
*path
)
2681 struct yaffs_dev
*dev
= NULL
;
2685 yaffsfs_SetError(-EFAULT
);
2689 if (yaffsfs_CheckPath(path
) < 0) {
2690 yaffsfs_SetError(-ENAMETOOLONG
);
2695 dev
= yaffsfs_FindDevice(path
, &dummy
);
2696 if (dev
&& dev
->is_mounted
) {
2697 retVal
= (dev
->param
.end_block
- dev
->param
.start_block
+ 1) -
2698 dev
->param
.n_reserved_blocks
;
2699 retVal
*= dev
->param
.chunks_per_block
;
2700 retVal
*= dev
->data_bytes_per_chunk
;
2703 yaffsfs_SetError(-EINVAL
);
2709 int yaffs_inodecount(const YCHAR
*path
)
2712 struct yaffs_dev
*dev
= NULL
;
2716 yaffsfs_SetError(-EFAULT
);
2720 if (yaffsfs_CheckPath(path
) < 0) {
2721 yaffsfs_SetError(-ENAMETOOLONG
);
2726 dev
= yaffsfs_FindDevice(path
, &dummy
);
2727 if (dev
&& dev
->is_mounted
) {
2728 int n_obj
= dev
->n_obj
;
2729 if (n_obj
> dev
->n_hardlinks
)
2730 retVal
= n_obj
- dev
->n_hardlinks
;
2734 yaffsfs_SetError(-EINVAL
);
2740 void yaffs_add_device(struct yaffs_dev
*dev
)
2742 struct list_head
*cfg
;
2743 /* First check that the device is not in the list. */
2745 list_for_each(cfg
, &yaffsfs_deviceList
) {
2746 if (dev
== list_entry(cfg
, struct yaffs_dev
, dev_list
))
2750 dev
->is_mounted
= 0;
2751 dev
->param
.remove_obj_fn
= yaffsfs_RemoveObjectCallback
;
2753 if (!dev
->dev_list
.next
)
2754 INIT_LIST_HEAD(&dev
->dev_list
);
2756 list_add(&dev
->dev_list
, &yaffsfs_deviceList
);
2759 void yaffs_remove_device(struct yaffs_dev
*dev
)
2761 list_del_init(&dev
->dev_list
);
2764 /* Functions to iterate through devices. NB Use with extreme care! */
2766 static struct list_head
*dev_iterator
;
2767 void yaffs_dev_rewind(void)
2769 dev_iterator
= yaffsfs_deviceList
.next
;
2772 struct yaffs_dev
*yaffs_next_dev(void)
2774 struct yaffs_dev
*retval
;
2778 if (dev_iterator
== &yaffsfs_deviceList
)
2781 retval
= list_entry(dev_iterator
, struct yaffs_dev
, dev_list
);
2782 dev_iterator
= dev_iterator
->next
;
2786 /* Directory search stuff. */
2788 static struct list_head search_contexts
;
2790 static void yaffsfs_SetDirRewound(struct yaffsfs_DirSearchContxt
*dsc
)
2794 dsc
->dirObj
->variant_type
== YAFFS_OBJECT_TYPE_DIRECTORY
) {
2798 if (list_empty(&dsc
->dirObj
->variant
.dir_variant
.children
))
2799 dsc
->nextReturn
= NULL
;
2802 list_entry(dsc
->dirObj
->variant
.dir_variant
.
2803 children
.next
, struct yaffs_obj
,
2806 /* Hey someone isn't playing nice! */
2810 static void yaffsfs_DirAdvance(struct yaffsfs_DirSearchContxt
*dsc
)
2814 dsc
->dirObj
->variant_type
== YAFFS_OBJECT_TYPE_DIRECTORY
) {
2816 if (dsc
->nextReturn
== NULL
||
2817 list_empty(&dsc
->dirObj
->variant
.dir_variant
.children
))
2818 dsc
->nextReturn
= NULL
;
2820 struct list_head
*next
= dsc
->nextReturn
->siblings
.next
;
2822 if (next
== &dsc
->dirObj
->variant
.dir_variant
.children
)
2823 dsc
->nextReturn
= NULL
; /* end of list */
2825 dsc
->nextReturn
= list_entry(next
,
2830 /* Hey someone isn't playing nice! */
2834 static void yaffsfs_RemoveObjectCallback(struct yaffs_obj
*obj
)
2837 struct list_head
*i
;
2838 struct yaffsfs_DirSearchContxt
*dsc
;
2840 /* if search contexts not initilised then skip */
2841 if (!search_contexts
.next
)
2844 /* Iterate through the directory search contexts.
2845 * If any are the one being removed, then advance the dsc to
2846 * the next one to prevent a hanging ptr.
2848 list_for_each(i
, &search_contexts
) {
2850 dsc
= list_entry(i
, struct yaffsfs_DirSearchContxt
,
2852 if (dsc
->nextReturn
== obj
)
2853 yaffsfs_DirAdvance(dsc
);
2859 yaffs_DIR
*yaffs_opendir(const YCHAR
*dirname
)
2861 yaffs_DIR
*dir
= NULL
;
2862 struct yaffs_obj
*obj
= NULL
;
2863 struct yaffsfs_DirSearchContxt
*dsc
= NULL
;
2868 yaffsfs_SetError(-EFAULT
);
2872 if (yaffsfs_CheckPath(dirname
) < 0) {
2873 yaffsfs_SetError(-ENAMETOOLONG
);
2879 obj
= yaffsfs_FindObject(NULL
, dirname
, 0, 1, NULL
, ¬Dir
, &loop
);
2882 yaffsfs_SetError(-ENOTDIR
);
2884 yaffsfs_SetError(-ELOOP
);
2886 yaffsfs_SetError(-ENOENT
);
2887 else if (obj
->variant_type
!= YAFFS_OBJECT_TYPE_DIRECTORY
)
2888 yaffsfs_SetError(-ENOTDIR
);
2892 for (i
= 0, dsc
= NULL
; i
< YAFFSFS_N_DSC
&& !dsc
; i
++) {
2893 if (!yaffsfs_dsc
[i
].inUse
)
2894 dsc
= &yaffsfs_dsc
[i
];
2897 dir
= (yaffs_DIR
*) dsc
;
2900 memset(dsc
, 0, sizeof(struct yaffsfs_DirSearchContxt
));
2903 yaffs_strncpy(dsc
->name
, dirname
, NAME_MAX
);
2904 INIT_LIST_HEAD(&dsc
->others
);
2906 if (!search_contexts
.next
)
2907 INIT_LIST_HEAD(&search_contexts
);
2909 list_add(&dsc
->others
, &search_contexts
);
2910 yaffsfs_SetDirRewound(dsc
);
2920 struct yaffs_dirent
*yaffs_readdir(yaffs_DIR
* dirp
)
2922 struct yaffsfs_DirSearchContxt
*dsc
;
2923 struct yaffs_dirent
*retVal
= NULL
;
2925 dsc
= (struct yaffsfs_DirSearchContxt
*) dirp
;
2928 if (dsc
&& dsc
->inUse
) {
2929 yaffsfs_SetError(0);
2930 if (dsc
->nextReturn
) {
2932 yaffs_get_equivalent_obj(dsc
->nextReturn
)->obj_id
;
2933 dsc
->de
.d_dont_use
= (unsigned)dsc
->nextReturn
;
2934 dsc
->de
.d_off
= dsc
->offset
++;
2935 yaffs_get_obj_name(dsc
->nextReturn
,
2936 dsc
->de
.d_name
, NAME_MAX
);
2937 if (yaffs_strnlen(dsc
->de
.d_name
, NAME_MAX
+ 1) == 0) {
2938 /* this should not happen! */
2939 yaffs_strcpy(dsc
->de
.d_name
, _Y("zz"));
2941 dsc
->de
.d_reclen
= sizeof(struct yaffs_dirent
);
2943 yaffsfs_DirAdvance(dsc
);
2947 yaffsfs_SetError(-EBADF
);
2955 void yaffs_rewinddir(yaffs_DIR
*dirp
)
2957 struct yaffsfs_DirSearchContxt
*dsc
;
2959 dsc
= (struct yaffsfs_DirSearchContxt
*) dirp
;
2963 yaffsfs_SetDirRewound(dsc
);
2968 int yaffs_closedir(yaffs_DIR
*dirp
)
2970 struct yaffsfs_DirSearchContxt
*dsc
;
2972 dsc
= (struct yaffsfs_DirSearchContxt
*) dirp
;
2975 yaffsfs_SetError(-EFAULT
);
2981 list_del(&dsc
->others
); /* unhook from list */
2986 /* End of directory stuff */
2988 int yaffs_symlink(const YCHAR
*oldpath
, const YCHAR
*newpath
)
2990 struct yaffs_obj
*parent
= NULL
;
2991 struct yaffs_obj
*obj
;
2994 int mode
= 0; /* ignore for now */
2998 if (!oldpath
|| !newpath
) {
2999 yaffsfs_SetError(-EFAULT
);
3003 if (yaffsfs_CheckPath(newpath
) < 0 || yaffsfs_CheckPath(oldpath
) < 0) {
3004 yaffsfs_SetError(-ENAMETOOLONG
);
3009 parent
= yaffsfs_FindDirectory(NULL
, newpath
, &name
, 0, ¬Dir
, &loop
);
3010 if (!parent
&& notDir
)
3011 yaffsfs_SetError(-ENOTDIR
);
3013 yaffsfs_SetError(-ELOOP
);
3014 else if (!parent
|| yaffs_strnlen(name
, 5) < 1)
3015 yaffsfs_SetError(-ENOENT
);
3016 else if (yaffsfs_TooManyObjects(parent
->my_dev
))
3017 yaffsfs_SetError(-ENFILE
);
3018 else if (parent
->my_dev
->read_only
)
3019 yaffsfs_SetError(-EROFS
);
3021 obj
= yaffs_create_symlink(parent
, name
, mode
, 0, 0, oldpath
);
3024 else if (yaffsfs_FindObject
3025 (NULL
, newpath
, 0, 0, NULL
, NULL
, NULL
))
3026 yaffsfs_SetError(-EEXIST
);
3028 yaffsfs_SetError(-ENOSPC
);
3037 int yaffs_readlink(const YCHAR
*path
, YCHAR
*buf
, int bufsiz
)
3039 struct yaffs_obj
*obj
= NULL
;
3040 struct yaffs_obj
*dir
= NULL
;
3045 if (!path
|| !buf
) {
3046 yaffsfs_SetError(-EFAULT
);
3052 obj
= yaffsfs_FindObject(NULL
, path
, 0, 1, &dir
, ¬Dir
, &loop
);
3055 yaffsfs_SetError(-ENOTDIR
);
3057 yaffsfs_SetError(-ELOOP
);
3058 else if (!dir
|| !obj
)
3059 yaffsfs_SetError(-ENOENT
);
3060 else if (obj
->variant_type
!= YAFFS_OBJECT_TYPE_SYMLINK
)
3061 yaffsfs_SetError(-EINVAL
);
3063 YCHAR
*alias
= obj
->variant
.symlink_variant
.alias
;
3064 memset(buf
, 0, bufsiz
);
3065 yaffs_strncpy(buf
, alias
, bufsiz
- 1);
3072 int yaffs_link(const YCHAR
*oldpath
, const YCHAR
*linkpath
)
3074 /* Creates a link called newpath to existing oldpath */
3075 struct yaffs_obj
*obj
= NULL
;
3076 struct yaffs_obj
*lnk
= NULL
;
3077 struct yaffs_obj
*obj_dir
= NULL
;
3078 struct yaffs_obj
*lnk_dir
= NULL
;
3086 if (!oldpath
|| !linkpath
) {
3087 yaffsfs_SetError(-EFAULT
);
3091 if (yaffsfs_CheckPath(linkpath
) < 0 || yaffsfs_CheckPath(oldpath
) < 0) {
3092 yaffsfs_SetError(-ENAMETOOLONG
);
3098 obj
= yaffsfs_FindObject(NULL
, oldpath
, 0, 1,
3099 &obj_dir
, ¬DirObj
, &objLoop
);
3100 lnk
= yaffsfs_FindObject(NULL
, linkpath
, 0, 0, NULL
, NULL
, NULL
);
3101 lnk_dir
= yaffsfs_FindDirectory(NULL
, linkpath
, &newname
,
3102 0, ¬DirLnk
, &lnkLoop
);
3104 if ((!obj_dir
&& notDirObj
) || (!lnk_dir
&& notDirLnk
))
3105 yaffsfs_SetError(-ENOTDIR
);
3106 else if (objLoop
|| lnkLoop
)
3107 yaffsfs_SetError(-ELOOP
);
3108 else if (!obj_dir
|| !lnk_dir
|| !obj
)
3109 yaffsfs_SetError(-ENOENT
);
3110 else if (obj
->my_dev
->read_only
)
3111 yaffsfs_SetError(-EROFS
);
3112 else if (yaffsfs_TooManyObjects(obj
->my_dev
))
3113 yaffsfs_SetError(-ENFILE
);
3115 yaffsfs_SetError(-EEXIST
);
3116 else if (lnk_dir
->my_dev
!= obj
->my_dev
)
3117 yaffsfs_SetError(-EXDEV
);
3119 retVal
= yaffsfs_CheckNameLength(newname
);
3122 lnk
= yaffs_link_obj(lnk_dir
, newname
, obj
);
3126 yaffsfs_SetError(-ENOSPC
);
3136 int yaffs_mknod(const YCHAR
*pathname
, mode_t mode
, dev_t dev
)
3138 pathname
= pathname
;
3142 yaffsfs_SetError(-EINVAL
);
3147 * D E B U G F U N C T I O N S
3152 * Returns number of handles attached to the object
3154 int yaffs_n_handles(const YCHAR
*path
)
3156 struct yaffs_obj
*obj
;
3159 yaffsfs_SetError(-EFAULT
);
3163 if (yaffsfs_CheckPath(path
) < 0) {
3164 yaffsfs_SetError(-ENAMETOOLONG
);
3168 obj
= yaffsfs_FindObject(NULL
, path
, 0, 1, NULL
, NULL
, NULL
);
3171 return yaffsfs_CountHandles(obj
);
3176 int yaffs_get_error(void)
3178 return yaffsfs_GetLastError();
3181 int yaffs_set_error(int error
)
3183 yaffsfs_SetError(error
);
3187 int yaffs_dump_dev(const YCHAR
*path
)
3194 struct yaffs_obj
*obj
= yaffsfs_FindRoot(path
, &rest
);
3197 struct yaffs_dev
*dev
= obj
->my_dev
;
3200 "n_page_writes.......... %d\n"
3201 "n_page_reads........... %d\n"
3202 "n_erasures....... %d\n"
3203 "n_gc_copies............ %d\n"
3204 "garbageCollections... %d\n"
3205 "passiveGarbageColl'ns %d\n"
3211 dev
->garbageCollections
, dev
->passiveGarbageCollections
);