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