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