1 /* 2 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. 3 * 4 * Copyright (C) 2002-2011 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 #include <div64.h> 15 #include "yaffsfs.h" 16 #include "yaffs_guts.h" 17 #include "yaffscfg.h" 18 #include "yportenv.h" 19 #include "yaffs_trace.h" 20 21 #define YAFFSFS_MAX_SYMLINK_DEREFERENCES 5 22 23 #ifndef NULL 24 #define NULL ((void *)0) 25 #endif 26 27 /* YAFFSFS_RW_SIZE must be a power of 2 */ 28 #define YAFFSFS_RW_SHIFT (13) 29 #define YAFFSFS_RW_SIZE (1<<YAFFSFS_RW_SHIFT) 30 31 /* Some forward references */ 32 static struct yaffs_obj *yaffsfs_FindObject(struct yaffs_obj *relativeDirectory, 33 const YCHAR *path, 34 int symDepth, int getEquiv, 35 struct yaffs_obj **dirOut, 36 int *notDir, int *loop); 37 38 static void yaffsfs_RemoveObjectCallback(struct yaffs_obj *obj); 39 40 unsigned int yaffs_wr_attempts; 41 42 /* 43 * Handle management. 44 * There are open inodes in struct yaffsfs_Inode. 45 * There are open file descriptors in yaffsfs_FileDes. 46 * There are open handles in yaffsfs_FileDes. 47 * 48 * Things are structured this way to be like the Linux VFS model 49 * so that interactions with the yaffs guts calls are similar. 50 * That means more common code paths and less special code. 51 * That means better testing etc. 52 * 53 * We have 3 layers because: 54 * A handle is different than an fd because you can use dup() 55 * to create a new handle that accesses the *same* fd. The two 56 * handles will use the same offset (part of the fd). We only close 57 * down the fd when there are no more handles accessing it. 58 * 59 * More than one fd can currently access one file, but each fd 60 * has its own permsiions and offset. 61 */ 62 63 struct yaffsfs_Inode { 64 int count; /* Number of handles accessing this inode */ 65 struct yaffs_obj *iObj; 66 }; 67 68 struct yaffsfs_FileDes { 69 u8 reading:1; 70 u8 writing:1; 71 u8 append:1; 72 u8 shareRead:1; 73 u8 shareWrite:1; 74 int inodeId:12; /* Index to corresponding yaffsfs_Inode */ 75 int handleCount:10; /* Number of handles for this fd */ 76 loff_t position; /* current position in file */ 77 }; 78 79 struct yaffsfs_Handle { 80 short int fdId; 81 short int useCount; 82 }; 83 84 85 struct yaffsfs_DirSearchContxt { 86 struct yaffs_dirent de; /* directory entry */ 87 YCHAR name[NAME_MAX + 1]; /* name of directory being searched */ 88 struct yaffs_obj *dirObj; /* ptr to directory being searched */ 89 struct yaffs_obj *nextReturn; /* obj returned by next readddir */ 90 struct list_head others; 91 int offset:20; 92 unsigned inUse:1; 93 }; 94 95 static struct yaffsfs_DirSearchContxt yaffsfs_dsc[YAFFSFS_N_DSC]; 96 static struct yaffsfs_Inode yaffsfs_inode[YAFFSFS_N_HANDLES]; 97 static struct yaffsfs_FileDes yaffsfs_fd[YAFFSFS_N_HANDLES]; 98 static struct yaffsfs_Handle yaffsfs_handle[YAFFSFS_N_HANDLES]; 99 100 static int yaffsfs_handlesInitialised; 101 102 unsigned yaffs_set_trace(unsigned tm) 103 { 104 yaffs_trace_mask = tm; 105 return yaffs_trace_mask; 106 } 107 108 unsigned yaffs_get_trace(void) 109 { 110 return yaffs_trace_mask; 111 } 112 113 /* 114 * yaffsfs_InitHandle 115 * Inilitalise handle management on start-up. 116 */ 117 118 static void yaffsfs_InitHandles(void) 119 { 120 int i; 121 if (yaffsfs_handlesInitialised) 122 return; 123 124 memset(yaffsfs_inode, 0, sizeof(yaffsfs_inode)); 125 memset(yaffsfs_fd, 0, sizeof(yaffsfs_fd)); 126 memset(yaffsfs_handle, 0, sizeof(yaffsfs_handle)); 127 memset(yaffsfs_dsc, 0, sizeof(yaffsfs_dsc)); 128 129 for (i = 0; i < YAFFSFS_N_HANDLES; i++) 130 yaffsfs_fd[i].inodeId = -1; 131 for (i = 0; i < YAFFSFS_N_HANDLES; i++) 132 yaffsfs_handle[i].fdId = -1; 133 } 134 135 static struct yaffsfs_Handle *yaffsfs_HandleToPointer(int h) 136 { 137 if (h >= 0 && h < YAFFSFS_N_HANDLES) 138 return &yaffsfs_handle[h]; 139 return NULL; 140 } 141 142 static struct yaffsfs_FileDes *yaffsfs_HandleToFileDes(int handle) 143 { 144 struct yaffsfs_Handle *h = yaffsfs_HandleToPointer(handle); 145 146 if (h && h->useCount > 0 && h->fdId >= 0 && h->fdId < YAFFSFS_N_HANDLES) 147 return &yaffsfs_fd[h->fdId]; 148 149 return NULL; 150 } 151 152 static struct yaffsfs_Inode *yaffsfs_HandleToInode(int handle) 153 { 154 struct yaffsfs_FileDes *fd = yaffsfs_HandleToFileDes(handle); 155 156 if (fd && fd->handleCount > 0 && 157 fd->inodeId >= 0 && fd->inodeId < YAFFSFS_N_HANDLES) 158 return &yaffsfs_inode[fd->inodeId]; 159 160 return NULL; 161 } 162 163 static struct yaffs_obj *yaffsfs_HandleToObject(int handle) 164 { 165 struct yaffsfs_Inode *in = yaffsfs_HandleToInode(handle); 166 167 if (in) 168 return in->iObj; 169 170 return NULL; 171 } 172 173 /* 174 * yaffsfs_FindInodeIdForObject 175 * Find the inode entry for an object, if it exists. 176 */ 177 178 static int yaffsfs_FindInodeIdForObject(struct yaffs_obj *obj) 179 { 180 int i; 181 int ret = -1; 182 183 if (obj) 184 obj = yaffs_get_equivalent_obj(obj); 185 186 /* Look for it in open inode table */ 187 for (i = 0; i < YAFFSFS_N_HANDLES && ret < 0; i++) { 188 if (yaffsfs_inode[i].iObj == obj) 189 ret = i; 190 } 191 return ret; 192 } 193 194 /* 195 * yaffsfs_GetInodeIdForObject 196 * Grab an inode entry when opening a new inode. 197 */ 198 static int yaffsfs_GetInodeIdForObject(struct yaffs_obj *obj) 199 { 200 int i; 201 int ret; 202 struct yaffsfs_Inode *in = NULL; 203 204 if (obj) 205 obj = yaffs_get_equivalent_obj(obj); 206 207 ret = yaffsfs_FindInodeIdForObject(obj); 208 209 for (i = 0; i < YAFFSFS_N_HANDLES && ret < 0; i++) { 210 if (!yaffsfs_inode[i].iObj) 211 ret = i; 212 } 213 214 if (ret >= 0) { 215 in = &yaffsfs_inode[ret]; 216 if (!in->iObj) 217 in->count = 0; 218 in->iObj = obj; 219 in->count++; 220 } 221 222 return ret; 223 } 224 225 static int yaffsfs_CountHandles(struct yaffs_obj *obj) 226 { 227 int i = yaffsfs_FindInodeIdForObject(obj); 228 229 if (i >= 0) 230 return yaffsfs_inode[i].count; 231 else 232 return 0; 233 } 234 235 static void yaffsfs_ReleaseInode(struct yaffsfs_Inode *in) 236 { 237 struct yaffs_obj *obj; 238 239 obj = in->iObj; 240 241 if (obj->unlinked) 242 yaffs_del_obj(obj); 243 244 obj->my_inode = NULL; 245 in->iObj = NULL; 246 247 } 248 249 static void yaffsfs_PutInode(int inodeId) 250 { 251 if (inodeId >= 0 && inodeId < YAFFSFS_N_HANDLES) { 252 struct yaffsfs_Inode *in = &yaffsfs_inode[inodeId]; 253 in->count--; 254 if (in->count <= 0) { 255 yaffsfs_ReleaseInode(in); 256 in->count = 0; 257 } 258 } 259 } 260 261 static int yaffsfs_NewHandle(struct yaffsfs_Handle **hptr) 262 { 263 int i; 264 struct yaffsfs_Handle *h; 265 266 for (i = 0; i < YAFFSFS_N_HANDLES; i++) { 267 h = &yaffsfs_handle[i]; 268 if (h->useCount < 1) { 269 memset(h, 0, sizeof(struct yaffsfs_Handle)); 270 h->fdId = -1; 271 h->useCount = 1; 272 if (hptr) 273 *hptr = h; 274 return i; 275 } 276 } 277 return -1; 278 } 279 280 static int yaffsfs_NewHandleAndFileDes(void) 281 { 282 int i; 283 struct yaffsfs_FileDes *fd; 284 struct yaffsfs_Handle *h = NULL; 285 int handle = yaffsfs_NewHandle(&h); 286 287 if (handle < 0) 288 return -1; 289 290 for (i = 0; i < YAFFSFS_N_HANDLES; i++) { 291 fd = &yaffsfs_fd[i]; 292 if (fd->handleCount < 1) { 293 memset(fd, 0, sizeof(struct yaffsfs_FileDes)); 294 fd->inodeId = -1; 295 fd->handleCount = 1; 296 h->fdId = i; 297 return handle; 298 } 299 } 300 301 /* Dump the handle because we could not get a fd */ 302 h->useCount = 0; 303 return -1; 304 } 305 306 /* 307 * yaffs_get_handle 308 * Increase use of handle when reading/writing a file 309 * Also gets the file descriptor. 310 */ 311 312 static int yaffsfs_GetHandle(int handle) 313 { 314 struct yaffsfs_Handle *h = yaffsfs_HandleToPointer(handle); 315 316 if (h && h->useCount > 0) { 317 h->useCount++; 318 return 0; 319 } 320 return -1; 321 } 322 323 /* 324 * yaffs_put_handle 325 * Let go of a handle when closing a file or aborting an open or 326 * ending a read or write. 327 */ 328 329 static int yaffsfs_PutFileDes(int fdId) 330 { 331 struct yaffsfs_FileDes *fd; 332 333 if (fdId >= 0 && fdId < YAFFSFS_N_HANDLES) { 334 fd = &yaffsfs_fd[fdId]; 335 fd->handleCount--; 336 if (fd->handleCount < 1) { 337 if (fd->inodeId >= 0) { 338 yaffsfs_PutInode(fd->inodeId); 339 fd->inodeId = -1; 340 } 341 } 342 } 343 return 0; 344 } 345 346 static int yaffsfs_PutHandle(int handle) 347 { 348 struct yaffsfs_Handle *h = yaffsfs_HandleToPointer(handle); 349 350 if (h && h->useCount > 0) { 351 h->useCount--; 352 if (h->useCount < 1) { 353 yaffsfs_PutFileDes(h->fdId); 354 h->fdId = -1; 355 } 356 } 357 358 return 0; 359 } 360 361 static void yaffsfs_BreakDeviceHandles(struct yaffs_dev *dev) 362 { 363 struct yaffsfs_FileDes *fd; 364 struct yaffsfs_Handle *h; 365 struct yaffs_obj *obj; 366 int i; 367 for (i = 0; i < YAFFSFS_N_HANDLES; i++) { 368 h = yaffsfs_HandleToPointer(i); 369 fd = yaffsfs_HandleToFileDes(i); 370 obj = yaffsfs_HandleToObject(i); 371 if (h && h->useCount > 0) { 372 h->useCount = 0; 373 h->fdId = 0; 374 } 375 if (fd && fd->handleCount > 0 && obj && obj->my_dev == dev) { 376 fd->handleCount = 0; 377 yaffsfs_PutInode(fd->inodeId); 378 fd->inodeId = -1; 379 } 380 } 381 } 382 383 /* 384 * Stuff to handle names. 385 */ 386 #ifdef CONFIG_YAFFS_CASE_INSENSITIVE 387 388 static int yaffs_toupper(YCHAR a) 389 { 390 if (a >= 'a' && a <= 'z') 391 return (a - 'a') + 'A'; 392 else 393 return a; 394 } 395 396 int yaffsfs_Match(YCHAR a, YCHAR b) 397 { 398 return (yaffs_toupper(a) == yaffs_toupper(b)); 399 } 400 #else 401 int yaffsfs_Match(YCHAR a, YCHAR b) 402 { 403 /* case sensitive */ 404 return (a == b); 405 } 406 #endif 407 408 int yaffsfs_IsPathDivider(YCHAR ch) 409 { 410 const YCHAR *str = YAFFS_PATH_DIVIDERS; 411 412 while (*str) { 413 if (*str == ch) 414 return 1; 415 str++; 416 } 417 418 return 0; 419 } 420 421 int yaffsfs_CheckNameLength(const char *name) 422 { 423 int retVal = 0; 424 425 int nameLength = yaffs_strnlen(name, YAFFS_MAX_NAME_LENGTH + 1); 426 427 if (nameLength == 0) { 428 yaffsfs_SetError(-ENOENT); 429 retVal = -1; 430 } else if (nameLength > YAFFS_MAX_NAME_LENGTH) { 431 yaffsfs_SetError(-ENAMETOOLONG); 432 retVal = -1; 433 } 434 435 return retVal; 436 } 437 438 static int yaffsfs_alt_dir_path(const YCHAR *path, YCHAR **ret_path) 439 { 440 YCHAR *alt_path = NULL; 441 int path_length; 442 int i; 443 444 /* 445 * We don't have a definition for max path length. 446 * We will use 3 * max name length instead. 447 */ 448 *ret_path = NULL; 449 path_length = yaffs_strnlen(path, (YAFFS_MAX_NAME_LENGTH + 1) * 3 + 1); 450 451 /* If the last character is a path divider, then we need to 452 * trim it back so that the name look-up works properly. 453 * eg. /foo/new_dir/ -> /foo/newdir 454 * Curveball: Need to handle multiple path dividers: 455 * eg. /foof/sdfse///// -> /foo/sdfse 456 */ 457 if (path_length > 0 && yaffsfs_IsPathDivider(path[path_length - 1])) { 458 alt_path = kmalloc(path_length + 1, 0); 459 if (!alt_path) 460 return -1; 461 yaffs_strcpy(alt_path, path); 462 for (i = path_length - 1; 463 i >= 0 && yaffsfs_IsPathDivider(alt_path[i]); i--) 464 alt_path[i] = (YCHAR) 0; 465 } 466 *ret_path = alt_path; 467 return 0; 468 } 469 470 LIST_HEAD(yaffsfs_deviceList); 471 472 /* 473 * yaffsfs_FindDevice 474 * yaffsfs_FindRoot 475 * Scan the configuration list to find the device 476 * Curveballs: Should match paths that end in '/' too 477 * Curveball2 Might have "/x/ and "/x/y". Need to return the longest match 478 */ 479 static struct yaffs_dev *yaffsfs_FindDevice(const YCHAR *path, 480 YCHAR **restOfPath) 481 { 482 struct list_head *cfg; 483 const YCHAR *leftOver; 484 const YCHAR *p; 485 struct yaffs_dev *retval = NULL; 486 struct yaffs_dev *dev = NULL; 487 int thisMatchLength; 488 int longestMatch = -1; 489 int matching; 490 491 /* 492 * Check all configs, choose the one that: 493 * 1) Actually matches a prefix (ie /a amd /abc will not match 494 * 2) Matches the longest. 495 */ 496 list_for_each(cfg, &yaffsfs_deviceList) { 497 dev = list_entry(cfg, struct yaffs_dev, dev_list); 498 leftOver = path; 499 p = dev->param.name; 500 thisMatchLength = 0; 501 matching = 1; 502 503 while (matching && *p && *leftOver) { 504 /* Skip over any /s */ 505 while (yaffsfs_IsPathDivider(*p)) 506 p++; 507 508 /* Skip over any /s */ 509 while (yaffsfs_IsPathDivider(*leftOver)) 510 leftOver++; 511 512 /* Now match the text part */ 513 while (matching && 514 *p && !yaffsfs_IsPathDivider(*p) && 515 *leftOver && !yaffsfs_IsPathDivider(*leftOver)) { 516 if (yaffsfs_Match(*p, *leftOver)) { 517 p++; 518 leftOver++; 519 thisMatchLength++; 520 } else { 521 matching = 0; 522 } 523 } 524 } 525 526 /* Skip over any /s in leftOver */ 527 while (yaffsfs_IsPathDivider(*leftOver)) 528 leftOver++; 529 530 /*Skip over any /s in p */ 531 while (yaffsfs_IsPathDivider(*p)) 532 p++; 533 534 /* p should now be at the end of the string if fully matched */ 535 if (*p) 536 matching = 0; 537 538 if (matching && (thisMatchLength > longestMatch)) { 539 /* Matched prefix */ 540 *restOfPath = (YCHAR *) leftOver; 541 retval = dev; 542 longestMatch = thisMatchLength; 543 } 544 545 } 546 return retval; 547 } 548 549 static int yaffsfs_CheckPath(const YCHAR *path) 550 { 551 int n = 0; 552 int divs = 0; 553 554 while (*path && n < YAFFS_MAX_NAME_LENGTH && divs < 100) { 555 if (yaffsfs_IsPathDivider(*path)) { 556 n = 0; 557 divs++; 558 } else 559 n++; 560 path++; 561 } 562 563 return (*path) ? -1 : 0; 564 } 565 566 /* FindMountPoint only returns a dev entry if the path is a mount point */ 567 static struct yaffs_dev *yaffsfs_FindMountPoint(const YCHAR *path) 568 { 569 struct yaffs_dev *dev; 570 YCHAR *restOfPath = NULL; 571 572 dev = yaffsfs_FindDevice(path, &restOfPath); 573 if (dev && restOfPath && *restOfPath) 574 dev = NULL; 575 return dev; 576 } 577 578 static struct yaffs_obj *yaffsfs_FindRoot(const YCHAR *path, 579 YCHAR **restOfPath) 580 { 581 struct yaffs_dev *dev; 582 583 dev = yaffsfs_FindDevice(path, restOfPath); 584 if (dev && dev->is_mounted) 585 return dev->root_dir; 586 587 return NULL; 588 } 589 590 static struct yaffs_obj *yaffsfs_FollowLink(struct yaffs_obj *obj, 591 int symDepth, int *loop) 592 { 593 594 if (obj) 595 obj = yaffs_get_equivalent_obj(obj); 596 597 while (obj && obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) { 598 YCHAR *alias = obj->variant.symlink_variant.alias; 599 600 if (yaffsfs_IsPathDivider(*alias)) 601 /* Starts with a /, need to scan from root up */ 602 obj = yaffsfs_FindObject(NULL, alias, symDepth++, 603 1, NULL, NULL, loop); 604 else 605 /* 606 * Relative to here so use the parent of the 607 * symlink as a start 608 */ 609 obj = yaffsfs_FindObject(obj->parent, alias, symDepth++, 610 1, NULL, NULL, loop); 611 } 612 return obj; 613 } 614 615 /* 616 * yaffsfs_FindDirectory 617 * Parse a path to determine the directory and the name within the directory. 618 * 619 * eg. "/data/xx/ff" --> puts name="ff" and returns the directory "/data/xx" 620 */ 621 static struct yaffs_obj *yaffsfs_DoFindDirectory(struct yaffs_obj *startDir, 622 const YCHAR *path, 623 YCHAR **name, int symDepth, 624 int *notDir, int *loop) 625 { 626 struct yaffs_obj *dir; 627 YCHAR *restOfPath; 628 YCHAR str[YAFFS_MAX_NAME_LENGTH + 1]; 629 int i; 630 631 if (symDepth > YAFFSFS_MAX_SYMLINK_DEREFERENCES) { 632 if (loop) 633 *loop = 1; 634 return NULL; 635 } 636 637 if (startDir) { 638 dir = startDir; 639 restOfPath = (YCHAR *) path; 640 } else 641 dir = yaffsfs_FindRoot(path, &restOfPath); 642 643 while (dir) { 644 /* 645 * parse off /. 646 * curve ball: also throw away surplus '/' 647 * eg. "/ram/x////ff" gets treated the same as "/ram/x/ff" 648 */ 649 while (yaffsfs_IsPathDivider(*restOfPath)) 650 restOfPath++; /* get rid of '/' */ 651 652 *name = restOfPath; 653 i = 0; 654 655 while (*restOfPath && !yaffsfs_IsPathDivider(*restOfPath)) { 656 if (i < YAFFS_MAX_NAME_LENGTH) { 657 str[i] = *restOfPath; 658 str[i + 1] = '\0'; 659 i++; 660 } 661 restOfPath++; 662 } 663 664 if (!*restOfPath) 665 /* got to the end of the string */ 666 return dir; 667 else { 668 if (yaffs_strcmp(str, _Y(".")) == 0) { 669 /* Do nothing */ 670 } else if (yaffs_strcmp(str, _Y("..")) == 0) { 671 dir = dir->parent; 672 } else { 673 dir = yaffs_find_by_name(dir, str); 674 675 dir = yaffsfs_FollowLink(dir, symDepth, loop); 676 677 if (dir && dir->variant_type != 678 YAFFS_OBJECT_TYPE_DIRECTORY) { 679 if (notDir) 680 *notDir = 1; 681 dir = NULL; 682 } 683 684 } 685 } 686 } 687 /* directory did not exist. */ 688 return NULL; 689 } 690 691 static struct yaffs_obj *yaffsfs_FindDirectory(struct yaffs_obj *relDir, 692 const YCHAR *path, 693 YCHAR **name, 694 int symDepth, 695 int *notDir, int *loop) 696 { 697 return yaffsfs_DoFindDirectory(relDir, path, name, symDepth, notDir, 698 loop); 699 } 700 701 /* 702 * yaffsfs_FindObject turns a path for an existing object into the object 703 */ 704 static struct yaffs_obj *yaffsfs_FindObject(struct yaffs_obj *relDir, 705 const YCHAR *path, int symDepth, 706 int getEquiv, 707 struct yaffs_obj **dirOut, 708 int *notDir, int *loop) 709 { 710 struct yaffs_obj *dir; 711 struct yaffs_obj *obj; 712 YCHAR *name; 713 714 dir = 715 yaffsfs_FindDirectory(relDir, path, &name, symDepth, notDir, loop); 716 717 if (dirOut) 718 *dirOut = dir; 719 720 if (dir && *name) 721 obj = yaffs_find_by_name(dir, name); 722 else 723 obj = dir; 724 725 if (getEquiv) 726 obj = yaffs_get_equivalent_obj(obj); 727 728 return obj; 729 } 730 731 /************************************************************************* 732 * Start of yaffsfs visible functions. 733 *************************************************************************/ 734 735 int yaffs_dup(int handle) 736 { 737 int newHandleNumber = -1; 738 struct yaffsfs_FileDes *existingFD = NULL; 739 struct yaffsfs_Handle *existingHandle = NULL; 740 struct yaffsfs_Handle *newHandle = NULL; 741 742 yaffsfs_Lock(); 743 existingHandle = yaffsfs_HandleToPointer(handle); 744 existingFD = yaffsfs_HandleToFileDes(handle); 745 if (existingFD) 746 newHandleNumber = yaffsfs_NewHandle(&newHandle); 747 if (newHandle) { 748 newHandle->fdId = existingHandle->fdId; 749 existingFD->handleCount++; 750 } 751 752 yaffsfs_Unlock(); 753 754 if (!existingFD) 755 yaffsfs_SetError(-EBADF); 756 else if (!newHandle) 757 yaffsfs_SetError(-ENOMEM); 758 759 return newHandleNumber; 760 761 } 762 763 static int yaffsfs_TooManyObjects(struct yaffs_dev *dev) 764 { 765 int current_objects = dev->n_obj - dev->n_deleted_files; 766 767 if (dev->param.max_objects && current_objects > dev->param.max_objects) 768 return 1; 769 else 770 return 0; 771 } 772 773 int yaffs_open_sharing(const YCHAR *path, int oflag, int mode, int sharing) 774 { 775 struct yaffs_obj *obj = NULL; 776 struct yaffs_obj *dir = NULL; 777 YCHAR *name; 778 int handle = -1; 779 struct yaffsfs_FileDes *fd = NULL; 780 int openDenied = 0; 781 int symDepth = 0; 782 int errorReported = 0; 783 int rwflags = oflag & (O_RDWR | O_RDONLY | O_WRONLY); 784 u8 shareRead = (sharing & YAFFS_SHARE_READ) ? 1 : 0; 785 u8 shareWrite = (sharing & YAFFS_SHARE_WRITE) ? 1 : 0; 786 u8 sharedReadAllowed; 787 u8 sharedWriteAllowed; 788 u8 alreadyReading; 789 u8 alreadyWriting; 790 u8 readRequested; 791 u8 writeRequested; 792 int notDir = 0; 793 int loop = 0; 794 795 if (!path) { 796 yaffsfs_SetError(-EFAULT); 797 return -1; 798 } 799 800 if (yaffsfs_CheckPath(path) < 0) { 801 yaffsfs_SetError(-ENAMETOOLONG); 802 return -1; 803 } 804 805 /* O_EXCL only has meaning if O_CREAT is specified */ 806 if (!(oflag & O_CREAT)) 807 oflag &= ~(O_EXCL); 808 809 /* O_TRUNC has no meaning if (O_CREAT | O_EXCL) is specified */ 810 if ((oflag & O_CREAT) & (oflag & O_EXCL)) 811 oflag &= ~(O_TRUNC); 812 813 /* Todo: Are there any more flag combos to sanitise ? */ 814 815 /* Figure out if reading or writing is requested */ 816 817 readRequested = (rwflags == O_RDWR || rwflags == O_RDONLY) ? 1 : 0; 818 writeRequested = (rwflags == O_RDWR || rwflags == O_WRONLY) ? 1 : 0; 819 820 yaffsfs_Lock(); 821 822 handle = yaffsfs_NewHandleAndFileDes(); 823 824 if (handle < 0) { 825 yaffsfs_SetError(-ENFILE); 826 errorReported = 1; 827 } else { 828 829 fd = yaffsfs_HandleToFileDes(handle); 830 831 /* try to find the exisiting object */ 832 obj = yaffsfs_FindObject(NULL, path, 0, 1, NULL, NULL, NULL); 833 834 obj = yaffsfs_FollowLink(obj, symDepth++, &loop); 835 836 if (obj && 837 obj->variant_type != YAFFS_OBJECT_TYPE_FILE && 838 obj->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) 839 obj = NULL; 840 841 if (obj) { 842 843 /* The file already exists or it might be a directory */ 844 845 /* A directory can't be opened as a file */ 846 if (obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) { 847 openDenied = 1; 848 yaffsfs_SetError(-EISDIR); 849 errorReported = 1; 850 } 851 852 /* Open should fail if O_CREAT and O_EXCL are specified 853 * for a file that exists. 854 */ 855 if (!errorReported && 856 (oflag & O_EXCL) && (oflag & O_CREAT)) { 857 openDenied = 1; 858 yaffsfs_SetError(-EEXIST); 859 errorReported = 1; 860 } 861 862 /* Check file permissions */ 863 if (readRequested && !(obj->yst_mode & S_IREAD)) 864 openDenied = 1; 865 866 if (writeRequested && !(obj->yst_mode & S_IWRITE)) 867 openDenied = 1; 868 869 if (!errorReported && writeRequested && 870 obj->my_dev->read_only) { 871 openDenied = 1; 872 yaffsfs_SetError(-EROFS); 873 errorReported = 1; 874 } 875 876 if (openDenied && !errorReported) { 877 yaffsfs_SetError(-EACCES); 878 errorReported = 1; 879 } 880 881 /* Check sharing of an existing object. */ 882 if (!openDenied) { 883 struct yaffsfs_FileDes *fdx; 884 int i; 885 886 sharedReadAllowed = 1; 887 sharedWriteAllowed = 1; 888 alreadyReading = 0; 889 alreadyWriting = 0; 890 for (i = 0; i < YAFFSFS_N_HANDLES; i++) { 891 fdx = &yaffsfs_fd[i]; 892 if (fdx->handleCount > 0 && 893 fdx->inodeId >= 0 && 894 yaffsfs_inode[fdx->inodeId].iObj 895 == obj) { 896 if (!fdx->shareRead) 897 sharedReadAllowed = 0; 898 if (!fdx->shareWrite) 899 sharedWriteAllowed = 0; 900 if (fdx->reading) 901 alreadyReading = 1; 902 if (fdx->writing) 903 alreadyWriting = 1; 904 } 905 } 906 907 if ((!sharedReadAllowed && readRequested) || 908 (!shareRead && alreadyReading) || 909 (!sharedWriteAllowed && writeRequested) || 910 (!shareWrite && alreadyWriting)) { 911 openDenied = 1; 912 yaffsfs_SetError(-EBUSY); 913 errorReported = 1; 914 } 915 } 916 917 } 918 919 /* If we could not open an existing object, then let's see if 920 * the directory exists. If not, error. 921 */ 922 if (!obj && !errorReported) { 923 dir = yaffsfs_FindDirectory(NULL, path, &name, 0, 924 ¬Dir, &loop); 925 if (!dir && notDir) { 926 yaffsfs_SetError(-ENOTDIR); 927 errorReported = 1; 928 } else if (loop) { 929 yaffsfs_SetError(-ELOOP); 930 errorReported = 1; 931 } else if (!dir) { 932 yaffsfs_SetError(-ENOENT); 933 errorReported = 1; 934 } 935 } 936 937 if (!obj && dir && !errorReported && (oflag & O_CREAT)) { 938 /* Let's see if we can create this file */ 939 if (dir->my_dev->read_only) { 940 yaffsfs_SetError(-EROFS); 941 errorReported = 1; 942 } else if (yaffsfs_TooManyObjects(dir->my_dev)) { 943 yaffsfs_SetError(-ENFILE); 944 errorReported = 1; 945 } else 946 obj = yaffs_create_file(dir, name, mode, 0, 0); 947 948 if (!obj && !errorReported) { 949 yaffsfs_SetError(-ENOSPC); 950 errorReported = 1; 951 } 952 } 953 954 if (!obj && dir && !errorReported && !(oflag & O_CREAT)) { 955 yaffsfs_SetError(-ENOENT); 956 errorReported = 1; 957 } 958 959 if (obj && !openDenied) { 960 int inodeId = yaffsfs_GetInodeIdForObject(obj); 961 962 if (inodeId < 0) { 963 /* 964 * Todo: Fix any problem if inodes run out, 965 * That can't happen if the number of inode 966 * items >= number of handles. 967 */ 968 } 969 970 fd->inodeId = inodeId; 971 fd->reading = readRequested; 972 fd->writing = writeRequested; 973 fd->append = (oflag & O_APPEND) ? 1 : 0; 974 fd->position = 0; 975 fd->shareRead = shareRead; 976 fd->shareWrite = shareWrite; 977 978 /* Hook inode to object */ 979 obj->my_inode = (void *)&yaffsfs_inode[inodeId]; 980 981 if ((oflag & O_TRUNC) && fd->writing) 982 yaffs_resize_file(obj, 0); 983 } else { 984 yaffsfs_PutHandle(handle); 985 if (!errorReported) 986 yaffsfs_SetError(0); /* Problem */ 987 handle = -1; 988 } 989 } 990 991 yaffsfs_Unlock(); 992 993 return handle; 994 } 995 996 int yaffs_open(const YCHAR *path, int oflag, int mode) 997 { 998 return yaffs_open_sharing(path, oflag, mode, 999 YAFFS_SHARE_READ | YAFFS_SHARE_WRITE); 1000 } 1001 1002 int yaffs_Dofsync(int handle, int datasync) 1003 { 1004 int retVal = -1; 1005 struct yaffs_obj *obj; 1006 1007 yaffsfs_Lock(); 1008 1009 obj = yaffsfs_HandleToObject(handle); 1010 1011 if (!obj) 1012 yaffsfs_SetError(-EBADF); 1013 else if (obj->my_dev->read_only) 1014 yaffsfs_SetError(-EROFS); 1015 else { 1016 yaffs_flush_file(obj, 1, datasync); 1017 retVal = 0; 1018 } 1019 1020 yaffsfs_Unlock(); 1021 1022 return retVal; 1023 } 1024 1025 int yaffs_fsync(int handle) 1026 { 1027 return yaffs_Dofsync(handle, 0); 1028 } 1029 1030 int yaffs_flush(int handle) 1031 { 1032 return yaffs_fsync(handle); 1033 } 1034 1035 int yaffs_fdatasync(int handle) 1036 { 1037 return yaffs_Dofsync(handle, 1); 1038 } 1039 1040 int yaffs_close(int handle) 1041 { 1042 struct yaffsfs_Handle *h = NULL; 1043 struct yaffs_obj *obj = NULL; 1044 int retVal = -1; 1045 1046 yaffsfs_Lock(); 1047 1048 h = yaffsfs_HandleToPointer(handle); 1049 obj = yaffsfs_HandleToObject(handle); 1050 1051 if (!h || !obj) 1052 yaffsfs_SetError(-EBADF); 1053 else { 1054 /* clean up */ 1055 yaffs_flush_file(obj, 1, 0); 1056 yaffsfs_PutHandle(handle); 1057 retVal = 0; 1058 } 1059 1060 yaffsfs_Unlock(); 1061 1062 return retVal; 1063 } 1064 1065 int yaffsfs_do_read(int handle, void *vbuf, unsigned int nbyte, 1066 int isPread, loff_t offset) 1067 { 1068 struct yaffsfs_FileDes *fd = NULL; 1069 struct yaffs_obj *obj = NULL; 1070 loff_t pos = 0; 1071 loff_t startPos = 0; 1072 loff_t endPos = 0; 1073 int nRead = 0; 1074 int nToRead = 0; 1075 int totalRead = 0; 1076 loff_t maxRead; 1077 u8 *buf = (u8 *) vbuf; 1078 1079 if (!vbuf) { 1080 yaffsfs_SetError(-EFAULT); 1081 return -1; 1082 } 1083 1084 yaffsfs_Lock(); 1085 fd = yaffsfs_HandleToFileDes(handle); 1086 obj = yaffsfs_HandleToObject(handle); 1087 1088 if (!fd || !obj) { 1089 /* bad handle */ 1090 yaffsfs_SetError(-EBADF); 1091 totalRead = -1; 1092 } else if (!fd->reading) { 1093 /* Not a reading handle */ 1094 yaffsfs_SetError(-EINVAL); 1095 totalRead = -1; 1096 } else if (nbyte > YAFFS_MAX_FILE_SIZE) { 1097 yaffsfs_SetError(-EINVAL); 1098 totalRead = -1; 1099 } else { 1100 if (isPread) 1101 startPos = offset; 1102 else 1103 startPos = fd->position; 1104 1105 pos = startPos; 1106 1107 if (yaffs_get_obj_length(obj) > pos) 1108 maxRead = yaffs_get_obj_length(obj) - pos; 1109 else 1110 maxRead = 0; 1111 1112 if (nbyte > maxRead) 1113 nbyte = maxRead; 1114 1115 yaffsfs_GetHandle(handle); 1116 1117 endPos = pos + nbyte; 1118 1119 if (pos < 0 || pos > YAFFS_MAX_FILE_SIZE || 1120 nbyte > YAFFS_MAX_FILE_SIZE || 1121 endPos < 0 || endPos > YAFFS_MAX_FILE_SIZE) { 1122 totalRead = -1; 1123 nbyte = 0; 1124 } 1125 1126 while (nbyte > 0) { 1127 nToRead = YAFFSFS_RW_SIZE - 1128 (pos & (YAFFSFS_RW_SIZE - 1)); 1129 if (nToRead > nbyte) 1130 nToRead = nbyte; 1131 1132 /* Tricky bit... 1133 * Need to reverify object in case the device was 1134 * unmounted in another thread. 1135 */ 1136 obj = yaffsfs_HandleToObject(handle); 1137 if (!obj) 1138 nRead = 0; 1139 else 1140 nRead = yaffs_file_rd(obj, buf, pos, nToRead); 1141 1142 if (nRead > 0) { 1143 totalRead += nRead; 1144 pos += nRead; 1145 buf += nRead; 1146 } 1147 1148 if (nRead == nToRead) 1149 nbyte -= nRead; 1150 else 1151 nbyte = 0; /* no more to read */ 1152 1153 if (nbyte > 0) { 1154 yaffsfs_Unlock(); 1155 yaffsfs_Lock(); 1156 } 1157 1158 } 1159 1160 yaffsfs_PutHandle(handle); 1161 1162 if (!isPread) { 1163 if (totalRead >= 0) 1164 fd->position = startPos + totalRead; 1165 else 1166 yaffsfs_SetError(-EINVAL); 1167 } 1168 1169 } 1170 1171 yaffsfs_Unlock(); 1172 1173 return (totalRead >= 0) ? totalRead : -1; 1174 1175 } 1176 1177 int yaffs_read(int handle, void *buf, unsigned int nbyte) 1178 { 1179 return yaffsfs_do_read(handle, buf, nbyte, 0, 0); 1180 } 1181 1182 int yaffs_pread(int handle, void *buf, unsigned int nbyte, loff_t offset) 1183 { 1184 return yaffsfs_do_read(handle, buf, nbyte, 1, offset); 1185 } 1186 1187 int yaffsfs_do_write(int handle, const void *vbuf, unsigned int nbyte, 1188 int isPwrite, loff_t offset) 1189 { 1190 struct yaffsfs_FileDes *fd = NULL; 1191 struct yaffs_obj *obj = NULL; 1192 loff_t pos = 0; 1193 loff_t startPos = 0; 1194 loff_t endPos; 1195 int nWritten = 0; 1196 int totalWritten = 0; 1197 int write_trhrough = 0; 1198 int nToWrite = 0; 1199 const u8 *buf = (const u8 *)vbuf; 1200 1201 if (!vbuf) { 1202 yaffsfs_SetError(-EFAULT); 1203 return -1; 1204 } 1205 1206 yaffsfs_Lock(); 1207 fd = yaffsfs_HandleToFileDes(handle); 1208 obj = yaffsfs_HandleToObject(handle); 1209 1210 if (!fd || !obj) { 1211 /* bad handle */ 1212 yaffsfs_SetError(-EBADF); 1213 totalWritten = -1; 1214 } else if (!fd->writing) { 1215 yaffsfs_SetError(-EINVAL); 1216 totalWritten = -1; 1217 } else if (obj->my_dev->read_only) { 1218 yaffsfs_SetError(-EROFS); 1219 totalWritten = -1; 1220 } else { 1221 if (fd->append) 1222 startPos = yaffs_get_obj_length(obj); 1223 else if (isPwrite) 1224 startPos = offset; 1225 else 1226 startPos = fd->position; 1227 1228 yaffsfs_GetHandle(handle); 1229 pos = startPos; 1230 endPos = pos + nbyte; 1231 1232 if (pos < 0 || pos > YAFFS_MAX_FILE_SIZE || 1233 nbyte > YAFFS_MAX_FILE_SIZE || 1234 endPos < 0 || endPos > YAFFS_MAX_FILE_SIZE) { 1235 totalWritten = -1; 1236 nbyte = 0; 1237 } 1238 1239 while (nbyte > 0) { 1240 1241 nToWrite = YAFFSFS_RW_SIZE - 1242 (pos & (YAFFSFS_RW_SIZE - 1)); 1243 if (nToWrite > nbyte) 1244 nToWrite = nbyte; 1245 1246 /* Tricky bit... 1247 * Need to reverify object in case the device was 1248 * remounted or unmounted in another thread. 1249 */ 1250 obj = yaffsfs_HandleToObject(handle); 1251 if (!obj || obj->my_dev->read_only) 1252 nWritten = 0; 1253 else 1254 nWritten = 1255 yaffs_wr_file(obj, buf, pos, nToWrite, 1256 write_trhrough); 1257 if (nWritten > 0) { 1258 totalWritten += nWritten; 1259 pos += nWritten; 1260 buf += nWritten; 1261 } 1262 1263 if (nWritten == nToWrite) 1264 nbyte -= nToWrite; 1265 else 1266 nbyte = 0; 1267 1268 if (nWritten < 1 && totalWritten < 1) { 1269 yaffsfs_SetError(-ENOSPC); 1270 totalWritten = -1; 1271 } 1272 1273 if (nbyte > 0) { 1274 yaffsfs_Unlock(); 1275 yaffsfs_Lock(); 1276 } 1277 } 1278 1279 yaffsfs_PutHandle(handle); 1280 1281 if (!isPwrite) { 1282 if (totalWritten > 0) 1283 fd->position = startPos + totalWritten; 1284 else 1285 yaffsfs_SetError(-EINVAL); 1286 } 1287 } 1288 1289 yaffsfs_Unlock(); 1290 1291 return (totalWritten >= 0) ? totalWritten : -1; 1292 } 1293 1294 int yaffs_write(int fd, const void *buf, unsigned int nbyte) 1295 { 1296 return yaffsfs_do_write(fd, buf, nbyte, 0, 0); 1297 } 1298 1299 int yaffs_pwrite(int fd, const void *buf, unsigned int nbyte, loff_t offset) 1300 { 1301 return yaffsfs_do_write(fd, buf, nbyte, 1, offset); 1302 } 1303 1304 int yaffs_truncate(const YCHAR *path, loff_t new_size) 1305 { 1306 struct yaffs_obj *obj = NULL; 1307 struct yaffs_obj *dir = NULL; 1308 int result = YAFFS_FAIL; 1309 int notDir = 0; 1310 int loop = 0; 1311 1312 if (!path) { 1313 yaffsfs_SetError(-EFAULT); 1314 return -1; 1315 } 1316 1317 if (yaffsfs_CheckPath(path) < 0) { 1318 yaffsfs_SetError(-ENAMETOOLONG); 1319 return -1; 1320 } 1321 1322 yaffsfs_Lock(); 1323 1324 obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, ¬Dir, &loop); 1325 obj = yaffsfs_FollowLink(obj, 0, &loop); 1326 1327 if (!dir && notDir) 1328 yaffsfs_SetError(-ENOTDIR); 1329 else if (loop) 1330 yaffsfs_SetError(-ELOOP); 1331 else if (!dir || !obj) 1332 yaffsfs_SetError(-ENOENT); 1333 else if (obj->my_dev->read_only) 1334 yaffsfs_SetError(-EROFS); 1335 else if (obj->variant_type != YAFFS_OBJECT_TYPE_FILE) 1336 yaffsfs_SetError(-EISDIR); 1337 else if (obj->my_dev->read_only) 1338 yaffsfs_SetError(-EROFS); 1339 else if (new_size < 0 || new_size > YAFFS_MAX_FILE_SIZE) 1340 yaffsfs_SetError(-EINVAL); 1341 else 1342 result = yaffs_resize_file(obj, new_size); 1343 1344 yaffsfs_Unlock(); 1345 1346 return (result) ? 0 : -1; 1347 } 1348 1349 int yaffs_ftruncate(int handle, loff_t new_size) 1350 { 1351 struct yaffsfs_FileDes *fd = NULL; 1352 struct yaffs_obj *obj = NULL; 1353 int result = 0; 1354 1355 yaffsfs_Lock(); 1356 fd = yaffsfs_HandleToFileDes(handle); 1357 obj = yaffsfs_HandleToObject(handle); 1358 1359 if (!fd || !obj) 1360 /* bad handle */ 1361 yaffsfs_SetError(-EBADF); 1362 else if (!fd->writing) 1363 yaffsfs_SetError(-EINVAL); 1364 else if (obj->my_dev->read_only) 1365 yaffsfs_SetError(-EROFS); 1366 else if (new_size < 0 || new_size > YAFFS_MAX_FILE_SIZE) 1367 yaffsfs_SetError(-EINVAL); 1368 else 1369 /* resize the file */ 1370 result = yaffs_resize_file(obj, new_size); 1371 yaffsfs_Unlock(); 1372 1373 return (result) ? 0 : -1; 1374 1375 } 1376 1377 loff_t yaffs_lseek(int handle, loff_t offset, int whence) 1378 { 1379 struct yaffsfs_FileDes *fd = NULL; 1380 struct yaffs_obj *obj = NULL; 1381 loff_t pos = -1; 1382 loff_t fSize = -1; 1383 1384 yaffsfs_Lock(); 1385 fd = yaffsfs_HandleToFileDes(handle); 1386 obj = yaffsfs_HandleToObject(handle); 1387 1388 if (!fd || !obj) 1389 yaffsfs_SetError(-EBADF); 1390 else if (offset > YAFFS_MAX_FILE_SIZE) 1391 yaffsfs_SetError(-EINVAL); 1392 else { 1393 if (whence == SEEK_SET) { 1394 if (offset >= 0) 1395 pos = offset; 1396 } else if (whence == SEEK_CUR) { 1397 if ((fd->position + offset) >= 0) 1398 pos = (fd->position + offset); 1399 } else if (whence == SEEK_END) { 1400 fSize = yaffs_get_obj_length(obj); 1401 if (fSize >= 0 && (fSize + offset) >= 0) 1402 pos = fSize + offset; 1403 } 1404 1405 if (pos >= 0 && pos <= YAFFS_MAX_FILE_SIZE) 1406 fd->position = pos; 1407 else { 1408 yaffsfs_SetError(-EINVAL); 1409 pos = -1; 1410 } 1411 } 1412 1413 yaffsfs_Unlock(); 1414 1415 return pos; 1416 } 1417 1418 int yaffsfs_DoUnlink(const YCHAR *path, int isDirectory) 1419 { 1420 struct yaffs_obj *dir = NULL; 1421 struct yaffs_obj *obj = NULL; 1422 YCHAR *name; 1423 int result = YAFFS_FAIL; 1424 int notDir = 0; 1425 int loop = 0; 1426 1427 if (!path) { 1428 yaffsfs_SetError(-EFAULT); 1429 return -1; 1430 } 1431 1432 if (yaffsfs_CheckPath(path) < 0) { 1433 yaffsfs_SetError(-ENAMETOOLONG); 1434 return -1; 1435 } 1436 1437 yaffsfs_Lock(); 1438 1439 obj = yaffsfs_FindObject(NULL, path, 0, 0, NULL, NULL, NULL); 1440 dir = yaffsfs_FindDirectory(NULL, path, &name, 0, ¬Dir, &loop); 1441 1442 if (!dir && notDir) 1443 yaffsfs_SetError(-ENOTDIR); 1444 else if (loop) 1445 yaffsfs_SetError(-ELOOP); 1446 else if (!dir) 1447 yaffsfs_SetError(-ENOENT); 1448 else if (yaffs_strncmp(name, _Y("."), 2) == 0) 1449 yaffsfs_SetError(-EINVAL); 1450 else if (!obj) 1451 yaffsfs_SetError(-ENOENT); 1452 else if (obj->my_dev->read_only) 1453 yaffsfs_SetError(-EROFS); 1454 else if (!isDirectory && 1455 obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) 1456 yaffsfs_SetError(-EISDIR); 1457 else if (isDirectory && 1458 obj->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) 1459 yaffsfs_SetError(-ENOTDIR); 1460 else if (isDirectory && obj == obj->my_dev->root_dir) 1461 yaffsfs_SetError(-EBUSY); /* Can't rmdir a root */ 1462 else { 1463 result = yaffs_unlinker(dir, name); 1464 1465 if (result == YAFFS_FAIL && isDirectory) 1466 yaffsfs_SetError(-ENOTEMPTY); 1467 } 1468 1469 yaffsfs_Unlock(); 1470 1471 return (result == YAFFS_FAIL) ? -1 : 0; 1472 } 1473 1474 int yaffs_unlink(const YCHAR *path) 1475 { 1476 return yaffsfs_DoUnlink(path, 0); 1477 } 1478 1479 int yaffs_rename(const YCHAR *oldPath, const YCHAR *newPath) 1480 { 1481 struct yaffs_obj *olddir = NULL; 1482 struct yaffs_obj *newdir = NULL; 1483 struct yaffs_obj *obj = NULL; 1484 struct yaffs_obj *newobj = NULL; 1485 YCHAR *oldname; 1486 YCHAR *newname; 1487 int result = YAFFS_FAIL; 1488 int rename_allowed = 1; 1489 int notOldDir = 0; 1490 int notNewDir = 0; 1491 int oldLoop = 0; 1492 int newLoop = 0; 1493 1494 YCHAR *alt_newpath = NULL; 1495 1496 if (!oldPath || !newPath) { 1497 yaffsfs_SetError(-EFAULT); 1498 return -1; 1499 } 1500 1501 if (yaffsfs_CheckPath(oldPath) < 0 || yaffsfs_CheckPath(newPath) < 0) { 1502 yaffsfs_SetError(-ENAMETOOLONG); 1503 return -1; 1504 } 1505 1506 if (yaffsfs_alt_dir_path(newPath, &alt_newpath) < 0) { 1507 yaffsfs_SetError(-ENOMEM); 1508 return -1; 1509 } 1510 if (alt_newpath) 1511 newPath = alt_newpath; 1512 1513 yaffsfs_Lock(); 1514 1515 olddir = yaffsfs_FindDirectory(NULL, oldPath, &oldname, 0, 1516 ¬OldDir, &oldLoop); 1517 newdir = yaffsfs_FindDirectory(NULL, newPath, &newname, 0, 1518 ¬NewDir, &newLoop); 1519 obj = yaffsfs_FindObject(NULL, oldPath, 0, 0, NULL, NULL, NULL); 1520 newobj = yaffsfs_FindObject(NULL, newPath, 0, 0, NULL, NULL, NULL); 1521 1522 /* If the object being renamed is a directory and the 1523 * path ended with a "/" then the olddir == obj. 1524 * We pass through NULL for the old name to tell the lower layers 1525 * to use olddir as the object. 1526 */ 1527 1528 if (olddir == obj) 1529 oldname = NULL; 1530 1531 if ((!olddir && notOldDir) || (!newdir && notNewDir)) { 1532 yaffsfs_SetError(-ENOTDIR); 1533 rename_allowed = 0; 1534 } else if (oldLoop || newLoop) { 1535 yaffsfs_SetError(-ELOOP); 1536 rename_allowed = 0; 1537 } else if (olddir && oldname && 1538 yaffs_strncmp(oldname, _Y("."), 2) == 0) { 1539 yaffsfs_SetError(-EINVAL); 1540 rename_allowed = 0; 1541 } else if (!olddir || !newdir || !obj) { 1542 yaffsfs_SetError(-ENOENT); 1543 rename_allowed = 0; 1544 } else if (obj->my_dev->read_only) { 1545 yaffsfs_SetError(-EROFS); 1546 rename_allowed = 0; 1547 } else if (yaffs_is_non_empty_dir(newobj)) { 1548 yaffsfs_SetError(-ENOTEMPTY); 1549 rename_allowed = 0; 1550 } else if (olddir->my_dev != newdir->my_dev) { 1551 /* Rename must be on same device */ 1552 yaffsfs_SetError(-EXDEV); 1553 rename_allowed = 0; 1554 } else if (obj && obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) { 1555 /* 1556 * It is a directory, check that it is not being renamed to 1557 * being its own decendent. 1558 * Do this by tracing from the new directory back to the root, 1559 * checking for obj 1560 */ 1561 1562 struct yaffs_obj *xx = newdir; 1563 1564 while (rename_allowed && xx) { 1565 if (xx == obj) 1566 rename_allowed = 0; 1567 xx = xx->parent; 1568 } 1569 if (!rename_allowed) 1570 yaffsfs_SetError(-EINVAL); 1571 } 1572 1573 if (rename_allowed) 1574 result = yaffs_rename_obj(olddir, oldname, newdir, newname); 1575 1576 yaffsfs_Unlock(); 1577 1578 kfree(alt_newpath); 1579 1580 return (result == YAFFS_FAIL) ? -1 : 0; 1581 } 1582 1583 static int yaffsfs_DoStat(struct yaffs_obj *obj, struct yaffs_stat *buf) 1584 { 1585 int retVal = -1; 1586 1587 obj = yaffs_get_equivalent_obj(obj); 1588 1589 if (obj && buf) { 1590 buf->st_dev = (int)obj->my_dev->os_context; 1591 buf->st_ino = obj->obj_id; 1592 buf->st_mode = obj->yst_mode & ~S_IFMT; 1593 1594 if (obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) 1595 buf->st_mode |= S_IFDIR; 1596 else if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) 1597 buf->st_mode |= S_IFLNK; 1598 else if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE) 1599 buf->st_mode |= S_IFREG; 1600 1601 buf->st_nlink = yaffs_get_obj_link_count(obj); 1602 buf->st_uid = 0; 1603 buf->st_gid = 0; 1604 buf->st_rdev = obj->yst_rdev; 1605 buf->st_size = yaffs_get_obj_length(obj); 1606 buf->st_blksize = obj->my_dev->data_bytes_per_chunk; 1607 buf->st_blocks = lldiv(buf->st_size + buf->st_blksize - 1, 1608 buf->st_blksize); 1609 #if CONFIG_YAFFS_WINCE 1610 buf->yst_wince_atime[0] = obj->win_atime[0]; 1611 buf->yst_wince_atime[1] = obj->win_atime[1]; 1612 buf->yst_wince_ctime[0] = obj->win_ctime[0]; 1613 buf->yst_wince_ctime[1] = obj->win_ctime[1]; 1614 buf->yst_wince_mtime[0] = obj->win_mtime[0]; 1615 buf->yst_wince_mtime[1] = obj->win_mtime[1]; 1616 #else 1617 buf->yst_atime = obj->yst_atime; 1618 buf->yst_ctime = obj->yst_ctime; 1619 buf->yst_mtime = obj->yst_mtime; 1620 #endif 1621 retVal = 0; 1622 } 1623 return retVal; 1624 } 1625 1626 static int yaffsfs_DoStatOrLStat(const YCHAR *path, 1627 struct yaffs_stat *buf, int doLStat) 1628 { 1629 struct yaffs_obj *obj = NULL; 1630 struct yaffs_obj *dir = NULL; 1631 int retVal = -1; 1632 int notDir = 0; 1633 int loop = 0; 1634 1635 if (!path || !buf) { 1636 yaffsfs_SetError(-EFAULT); 1637 return -1; 1638 } 1639 1640 if (yaffsfs_CheckPath(path) < 0) { 1641 yaffsfs_SetError(-ENAMETOOLONG); 1642 return -1; 1643 } 1644 1645 yaffsfs_Lock(); 1646 1647 obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, ¬Dir, &loop); 1648 1649 if (!doLStat && obj) 1650 obj = yaffsfs_FollowLink(obj, 0, &loop); 1651 1652 if (!dir && notDir) 1653 yaffsfs_SetError(-ENOTDIR); 1654 else if (loop) 1655 yaffsfs_SetError(-ELOOP); 1656 else if (!dir || !obj) 1657 yaffsfs_SetError(-ENOENT); 1658 else 1659 retVal = yaffsfs_DoStat(obj, buf); 1660 1661 yaffsfs_Unlock(); 1662 1663 return retVal; 1664 1665 } 1666 1667 int yaffs_stat(const YCHAR *path, struct yaffs_stat *buf) 1668 { 1669 return yaffsfs_DoStatOrLStat(path, buf, 0); 1670 } 1671 1672 int yaffs_lstat(const YCHAR *path, struct yaffs_stat *buf) 1673 { 1674 return yaffsfs_DoStatOrLStat(path, buf, 1); 1675 } 1676 1677 int yaffs_fstat(int fd, struct yaffs_stat *buf) 1678 { 1679 struct yaffs_obj *obj; 1680 1681 int retVal = -1; 1682 1683 if (!buf) { 1684 yaffsfs_SetError(-EFAULT); 1685 return -1; 1686 } 1687 1688 yaffsfs_Lock(); 1689 obj = yaffsfs_HandleToObject(fd); 1690 1691 if (obj) 1692 retVal = yaffsfs_DoStat(obj, buf); 1693 else 1694 /* bad handle */ 1695 yaffsfs_SetError(-EBADF); 1696 1697 yaffsfs_Unlock(); 1698 1699 return retVal; 1700 } 1701 1702 static int yaffsfs_DoUtime(struct yaffs_obj *obj, 1703 const struct yaffs_utimbuf *buf) 1704 { 1705 int retVal = -1; 1706 int result; 1707 1708 struct yaffs_utimbuf local; 1709 1710 obj = yaffs_get_equivalent_obj(obj); 1711 1712 if (obj && obj->my_dev->read_only) { 1713 yaffsfs_SetError(-EROFS); 1714 return -1; 1715 } 1716 1717 if (!buf) { 1718 local.actime = Y_CURRENT_TIME; 1719 local.modtime = local.actime; 1720 buf = &local; 1721 } 1722 1723 if (obj) { 1724 obj->yst_atime = buf->actime; 1725 obj->yst_mtime = buf->modtime; 1726 obj->dirty = 1; 1727 result = yaffs_flush_file(obj, 0, 0); 1728 retVal = result == YAFFS_OK ? 0 : -1; 1729 } 1730 1731 return retVal; 1732 } 1733 1734 int yaffs_utime(const YCHAR *path, const struct yaffs_utimbuf *buf) 1735 { 1736 struct yaffs_obj *obj = NULL; 1737 struct yaffs_obj *dir = NULL; 1738 int retVal = -1; 1739 int notDir = 0; 1740 int loop = 0; 1741 1742 if (!path) { 1743 yaffsfs_SetError(-EFAULT); 1744 return -1; 1745 } 1746 1747 if (yaffsfs_CheckPath(path) < 0) { 1748 yaffsfs_SetError(-ENAMETOOLONG); 1749 return -1; 1750 } 1751 1752 yaffsfs_Lock(); 1753 1754 obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, ¬Dir, &loop); 1755 1756 if (!dir && notDir) 1757 yaffsfs_SetError(-ENOTDIR); 1758 else if (loop) 1759 yaffsfs_SetError(-ELOOP); 1760 else if (!dir || !obj) 1761 yaffsfs_SetError(-ENOENT); 1762 else 1763 retVal = yaffsfs_DoUtime(obj, buf); 1764 1765 yaffsfs_Unlock(); 1766 1767 return retVal; 1768 1769 } 1770 1771 int yaffs_futime(int fd, const struct yaffs_utimbuf *buf) 1772 { 1773 struct yaffs_obj *obj; 1774 1775 int retVal = -1; 1776 1777 yaffsfs_Lock(); 1778 obj = yaffsfs_HandleToObject(fd); 1779 1780 if (obj) 1781 retVal = yaffsfs_DoUtime(obj, buf); 1782 else 1783 /* bad handle */ 1784 yaffsfs_SetError(-EBADF); 1785 1786 yaffsfs_Unlock(); 1787 1788 return retVal; 1789 } 1790 1791 #ifndef CONFIG_YAFFS_WINCE 1792 /* xattrib functions */ 1793 1794 static int yaffs_do_setxattr(const YCHAR *path, const char *name, 1795 const void *data, int size, int flags, int follow) 1796 { 1797 struct yaffs_obj *obj; 1798 struct yaffs_obj *dir; 1799 int notDir = 0; 1800 int loop = 0; 1801 1802 int retVal = -1; 1803 1804 if (!path || !name || !data) { 1805 yaffsfs_SetError(-EFAULT); 1806 return -1; 1807 } 1808 1809 if (yaffsfs_CheckPath(path) < 0) { 1810 yaffsfs_SetError(-ENAMETOOLONG); 1811 return -1; 1812 } 1813 1814 yaffsfs_Lock(); 1815 1816 obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, ¬Dir, &loop); 1817 1818 if (follow) 1819 obj = yaffsfs_FollowLink(obj, 0, &loop); 1820 1821 if (!dir && notDir) 1822 yaffsfs_SetError(-ENOTDIR); 1823 else if (loop) 1824 yaffsfs_SetError(-ELOOP); 1825 else if (!dir || !obj) 1826 yaffsfs_SetError(-ENOENT); 1827 else { 1828 retVal = yaffs_set_xattrib(obj, name, data, size, flags); 1829 if (retVal < 0) { 1830 yaffsfs_SetError(retVal); 1831 retVal = -1; 1832 } 1833 } 1834 1835 yaffsfs_Unlock(); 1836 1837 return retVal; 1838 1839 } 1840 1841 int yaffs_setxattr(const YCHAR *path, const char *name, 1842 const void *data, int size, int flags) 1843 { 1844 return yaffs_do_setxattr(path, name, data, size, flags, 1); 1845 } 1846 1847 int yaffs_lsetxattr(const YCHAR *path, const char *name, 1848 const void *data, int size, int flags) 1849 { 1850 return yaffs_do_setxattr(path, name, data, size, flags, 0); 1851 } 1852 1853 int yaffs_fsetxattr(int fd, const char *name, 1854 const void *data, int size, int flags) 1855 { 1856 struct yaffs_obj *obj; 1857 1858 int retVal = -1; 1859 1860 if (!name || !data) { 1861 yaffsfs_SetError(-EFAULT); 1862 return -1; 1863 } 1864 1865 yaffsfs_Lock(); 1866 obj = yaffsfs_HandleToObject(fd); 1867 1868 if (!obj) 1869 yaffsfs_SetError(-EBADF); 1870 else { 1871 retVal = yaffs_set_xattrib(obj, name, data, size, flags); 1872 if (retVal < 0) { 1873 yaffsfs_SetError(retVal); 1874 retVal = -1; 1875 } 1876 } 1877 1878 yaffsfs_Unlock(); 1879 1880 return retVal; 1881 } 1882 1883 static int yaffs_do_getxattr(const YCHAR *path, const char *name, 1884 void *data, int size, int follow) 1885 { 1886 struct yaffs_obj *obj; 1887 struct yaffs_obj *dir; 1888 int retVal = -1; 1889 int notDir = 0; 1890 int loop = 0; 1891 1892 if (!path || !name || !data) { 1893 yaffsfs_SetError(-EFAULT); 1894 return -1; 1895 } 1896 1897 if (yaffsfs_CheckPath(path) < 0) { 1898 yaffsfs_SetError(-ENAMETOOLONG); 1899 return -1; 1900 } 1901 1902 yaffsfs_Lock(); 1903 1904 obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, ¬Dir, &loop); 1905 1906 if (follow) 1907 obj = yaffsfs_FollowLink(obj, 0, &loop); 1908 1909 if (!dir && notDir) 1910 yaffsfs_SetError(-ENOTDIR); 1911 else if (loop) 1912 yaffsfs_SetError(-ELOOP); 1913 else if (!dir || !obj) 1914 yaffsfs_SetError(-ENOENT); 1915 else { 1916 retVal = yaffs_get_xattrib(obj, name, data, size); 1917 if (retVal < 0) { 1918 yaffsfs_SetError(retVal); 1919 retVal = -1; 1920 } 1921 } 1922 yaffsfs_Unlock(); 1923 1924 return retVal; 1925 1926 } 1927 1928 int yaffs_getxattr(const YCHAR *path, const char *name, void *data, int size) 1929 { 1930 return yaffs_do_getxattr(path, name, data, size, 1); 1931 } 1932 1933 int yaffs_lgetxattr(const YCHAR *path, const char *name, void *data, int size) 1934 { 1935 return yaffs_do_getxattr(path, name, data, size, 0); 1936 } 1937 1938 int yaffs_fgetxattr(int fd, const char *name, void *data, int size) 1939 { 1940 struct yaffs_obj *obj; 1941 1942 int retVal = -1; 1943 1944 if (!name || !data) { 1945 yaffsfs_SetError(-EFAULT); 1946 return -1; 1947 } 1948 1949 yaffsfs_Lock(); 1950 obj = yaffsfs_HandleToObject(fd); 1951 1952 if (obj) { 1953 retVal = yaffs_get_xattrib(obj, name, data, size); 1954 if (retVal < 0) { 1955 yaffsfs_SetError(retVal); 1956 retVal = -1; 1957 } 1958 } else 1959 /* bad handle */ 1960 yaffsfs_SetError(-EBADF); 1961 1962 yaffsfs_Unlock(); 1963 1964 return retVal; 1965 } 1966 1967 static int yaffs_do_listxattr(const YCHAR *path, char *data, 1968 int size, int follow) 1969 { 1970 struct yaffs_obj *obj = NULL; 1971 struct yaffs_obj *dir = NULL; 1972 int retVal = -1; 1973 int notDir = 0; 1974 int loop = 0; 1975 1976 if (!path || !data) { 1977 yaffsfs_SetError(-EFAULT); 1978 return -1; 1979 } 1980 1981 if (yaffsfs_CheckPath(path) < 0) { 1982 yaffsfs_SetError(-ENAMETOOLONG); 1983 return -1; 1984 } 1985 1986 yaffsfs_Lock(); 1987 1988 obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, ¬Dir, &loop); 1989 1990 if (follow) 1991 obj = yaffsfs_FollowLink(obj, 0, &loop); 1992 1993 if (!dir && notDir) 1994 yaffsfs_SetError(-ENOTDIR); 1995 else if (loop) 1996 yaffsfs_SetError(-ELOOP); 1997 else if (!dir || !obj) 1998 yaffsfs_SetError(-ENOENT); 1999 else { 2000 retVal = yaffs_list_xattrib(obj, data, size); 2001 if (retVal < 0) { 2002 yaffsfs_SetError(retVal); 2003 retVal = -1; 2004 } 2005 } 2006 2007 yaffsfs_Unlock(); 2008 2009 return retVal; 2010 2011 } 2012 2013 int yaffs_listxattr(const YCHAR *path, char *data, int size) 2014 { 2015 return yaffs_do_listxattr(path, data, size, 1); 2016 } 2017 2018 int yaffs_llistxattr(const YCHAR *path, char *data, int size) 2019 { 2020 return yaffs_do_listxattr(path, data, size, 0); 2021 } 2022 2023 int yaffs_flistxattr(int fd, char *data, int size) 2024 { 2025 struct yaffs_obj *obj; 2026 2027 int retVal = -1; 2028 2029 if (!data) { 2030 yaffsfs_SetError(-EFAULT); 2031 return -1; 2032 } 2033 2034 yaffsfs_Lock(); 2035 obj = yaffsfs_HandleToObject(fd); 2036 2037 if (obj) { 2038 retVal = yaffs_list_xattrib(obj, data, size); 2039 if (retVal < 0) { 2040 yaffsfs_SetError(retVal); 2041 retVal = -1; 2042 } 2043 } else 2044 /* bad handle */ 2045 yaffsfs_SetError(-EBADF); 2046 2047 yaffsfs_Unlock(); 2048 2049 return retVal; 2050 } 2051 2052 static int yaffs_do_removexattr(const YCHAR *path, const char *name, 2053 int follow) 2054 { 2055 struct yaffs_obj *obj = NULL; 2056 struct yaffs_obj *dir = NULL; 2057 int notDir = 0; 2058 int loop = 0; 2059 int retVal = -1; 2060 2061 if (!path || !name) { 2062 yaffsfs_SetError(-EFAULT); 2063 return -1; 2064 } 2065 2066 if (yaffsfs_CheckPath(path) < 0) { 2067 yaffsfs_SetError(-ENAMETOOLONG); 2068 return -1; 2069 } 2070 2071 yaffsfs_Lock(); 2072 2073 obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, ¬Dir, &loop); 2074 2075 if (follow) 2076 obj = yaffsfs_FollowLink(obj, 0, &loop); 2077 2078 if (!dir && notDir) 2079 yaffsfs_SetError(-ENOTDIR); 2080 else if (loop) 2081 yaffsfs_SetError(-ELOOP); 2082 else if (!dir || !obj) 2083 yaffsfs_SetError(-ENOENT); 2084 else { 2085 retVal = yaffs_remove_xattrib(obj, name); 2086 if (retVal < 0) { 2087 yaffsfs_SetError(retVal); 2088 retVal = -1; 2089 } 2090 } 2091 2092 yaffsfs_Unlock(); 2093 2094 return retVal; 2095 2096 } 2097 2098 int yaffs_removexattr(const YCHAR *path, const char *name) 2099 { 2100 return yaffs_do_removexattr(path, name, 1); 2101 } 2102 2103 int yaffs_lremovexattr(const YCHAR *path, const char *name) 2104 { 2105 return yaffs_do_removexattr(path, name, 0); 2106 } 2107 2108 int yaffs_fremovexattr(int fd, const char *name) 2109 { 2110 struct yaffs_obj *obj; 2111 2112 int retVal = -1; 2113 2114 if (!name) { 2115 yaffsfs_SetError(-EFAULT); 2116 return -1; 2117 } 2118 2119 yaffsfs_Lock(); 2120 obj = yaffsfs_HandleToObject(fd); 2121 2122 if (obj) { 2123 retVal = yaffs_remove_xattrib(obj, name); 2124 if (retVal < 0) { 2125 yaffsfs_SetError(retVal); 2126 retVal = -1; 2127 } 2128 } else 2129 /* bad handle */ 2130 yaffsfs_SetError(-EBADF); 2131 2132 yaffsfs_Unlock(); 2133 2134 return retVal; 2135 } 2136 #endif 2137 2138 #ifdef CONFIG_YAFFS_WINCE 2139 int yaffs_get_wince_times(int fd, unsigned *wctime, 2140 unsigned *watime, unsigned *wmtime) 2141 { 2142 struct yaffs_obj *obj; 2143 2144 int retVal = -1; 2145 2146 yaffsfs_Lock(); 2147 obj = yaffsfs_HandleToObject(fd); 2148 2149 if (obj) { 2150 2151 if (wctime) { 2152 wctime[0] = obj->win_ctime[0]; 2153 wctime[1] = obj->win_ctime[1]; 2154 } 2155 if (watime) { 2156 watime[0] = obj->win_atime[0]; 2157 watime[1] = obj->win_atime[1]; 2158 } 2159 if (wmtime) { 2160 wmtime[0] = obj->win_mtime[0]; 2161 wmtime[1] = obj->win_mtime[1]; 2162 } 2163 2164 retVal = 0; 2165 } else 2166 /* bad handle */ 2167 yaffsfs_SetError(-EBADF); 2168 2169 yaffsfs_Unlock(); 2170 2171 return retVal; 2172 } 2173 2174 int yaffs_set_wince_times(int fd, 2175 const unsigned *wctime, 2176 const unsigned *watime, const unsigned *wmtime) 2177 { 2178 struct yaffs_obj *obj; 2179 int result; 2180 int retVal = -1; 2181 2182 yaffsfs_Lock(); 2183 obj = yaffsfs_HandleToObject(fd); 2184 2185 if (obj) { 2186 2187 if (wctime) { 2188 obj->win_ctime[0] = wctime[0]; 2189 obj->win_ctime[1] = wctime[1]; 2190 } 2191 if (watime) { 2192 obj->win_atime[0] = watime[0]; 2193 obj->win_atime[1] = watime[1]; 2194 } 2195 if (wmtime) { 2196 obj->win_mtime[0] = wmtime[0]; 2197 obj->win_mtime[1] = wmtime[1]; 2198 } 2199 2200 obj->dirty = 1; 2201 result = yaffs_flush_file(obj, 0, 0); 2202 retVal = 0; 2203 } else 2204 /* bad handle */ 2205 yaffsfs_SetError(-EBADF); 2206 2207 yaffsfs_Unlock(); 2208 2209 return retVal; 2210 } 2211 2212 #endif 2213 2214 static int yaffsfs_DoChMod(struct yaffs_obj *obj, mode_t mode) 2215 { 2216 int result = -1; 2217 2218 if (obj) 2219 obj = yaffs_get_equivalent_obj(obj); 2220 2221 if (obj) { 2222 obj->yst_mode = mode; 2223 obj->dirty = 1; 2224 result = yaffs_flush_file(obj, 0, 0); 2225 } 2226 2227 return result == YAFFS_OK ? 0 : -1; 2228 } 2229 2230 int yaffs_access(const YCHAR *path, int amode) 2231 { 2232 struct yaffs_obj *obj = NULL; 2233 struct yaffs_obj *dir = NULL; 2234 int notDir = 0; 2235 int loop = 0; 2236 int retval = -1; 2237 2238 if (!path) { 2239 yaffsfs_SetError(-EFAULT); 2240 return -1; 2241 } 2242 2243 if (yaffsfs_CheckPath(path) < 0) { 2244 yaffsfs_SetError(-ENAMETOOLONG); 2245 return -1; 2246 } 2247 2248 if (amode & ~(R_OK | W_OK | X_OK)) { 2249 yaffsfs_SetError(-EINVAL); 2250 return -1; 2251 } 2252 2253 yaffsfs_Lock(); 2254 2255 obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, ¬Dir, &loop); 2256 obj = yaffsfs_FollowLink(obj, 0, &loop); 2257 2258 if (!dir && notDir) 2259 yaffsfs_SetError(-ENOTDIR); 2260 else if (loop) 2261 yaffsfs_SetError(-ELOOP); 2262 else if (!dir || !obj) 2263 yaffsfs_SetError(-ENOENT); 2264 else if ((amode & W_OK) && obj->my_dev->read_only) 2265 yaffsfs_SetError(-EROFS); 2266 else { 2267 int access_ok = 1; 2268 2269 if ((amode & R_OK) && !(obj->yst_mode & S_IREAD)) 2270 access_ok = 0; 2271 if ((amode & W_OK) && !(obj->yst_mode & S_IWRITE)) 2272 access_ok = 0; 2273 if ((amode & X_OK) && !(obj->yst_mode & S_IEXEC)) 2274 access_ok = 0; 2275 2276 if (!access_ok) 2277 yaffsfs_SetError(-EACCES); 2278 else 2279 retval = 0; 2280 } 2281 2282 yaffsfs_Unlock(); 2283 2284 return retval; 2285 2286 } 2287 2288 int yaffs_chmod(const YCHAR *path, mode_t mode) 2289 { 2290 struct yaffs_obj *obj = NULL; 2291 struct yaffs_obj *dir = NULL; 2292 int retVal = -1; 2293 int notDir = 0; 2294 int loop = 0; 2295 2296 if (!path) { 2297 yaffsfs_SetError(-EFAULT); 2298 return -1; 2299 } 2300 2301 if (yaffsfs_CheckPath(path) < 0) { 2302 yaffsfs_SetError(-ENAMETOOLONG); 2303 return -1; 2304 } 2305 2306 if (mode & ~(0777)) { 2307 yaffsfs_SetError(-EINVAL); 2308 return -1; 2309 } 2310 2311 yaffsfs_Lock(); 2312 2313 obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, ¬Dir, &loop); 2314 obj = yaffsfs_FollowLink(obj, 0, &loop); 2315 2316 if (!dir && notDir) 2317 yaffsfs_SetError(-ENOTDIR); 2318 else if (loop) 2319 yaffsfs_SetError(-ELOOP); 2320 else if (!dir || !obj) 2321 yaffsfs_SetError(-ENOENT); 2322 else if (obj->my_dev->read_only) 2323 yaffsfs_SetError(-EROFS); 2324 else 2325 retVal = yaffsfs_DoChMod(obj, mode); 2326 2327 yaffsfs_Unlock(); 2328 2329 return retVal; 2330 2331 } 2332 2333 int yaffs_fchmod(int fd, mode_t mode) 2334 { 2335 struct yaffs_obj *obj; 2336 int retVal = -1; 2337 2338 if (mode & ~(0777)) { 2339 yaffsfs_SetError(-EINVAL); 2340 return -1; 2341 } 2342 2343 yaffsfs_Lock(); 2344 obj = yaffsfs_HandleToObject(fd); 2345 2346 if (!obj) 2347 yaffsfs_SetError(-EBADF); 2348 else if (obj->my_dev->read_only) 2349 yaffsfs_SetError(-EROFS); 2350 else 2351 retVal = yaffsfs_DoChMod(obj, mode); 2352 2353 yaffsfs_Unlock(); 2354 2355 return retVal; 2356 } 2357 2358 int yaffs_mkdir(const YCHAR *path, mode_t mode) 2359 { 2360 struct yaffs_obj *parent = NULL; 2361 struct yaffs_obj *dir = NULL; 2362 YCHAR *name; 2363 YCHAR *alt_path = NULL; 2364 int retVal = -1; 2365 int notDir = 0; 2366 int loop = 0; 2367 2368 if (!path) { 2369 yaffsfs_SetError(-EFAULT); 2370 return -1; 2371 } 2372 2373 if (yaffsfs_CheckPath(path) < 0) { 2374 yaffsfs_SetError(-ENAMETOOLONG); 2375 return -1; 2376 } 2377 2378 if (yaffsfs_alt_dir_path(path, &alt_path) < 0) { 2379 yaffsfs_SetError(-ENOMEM); 2380 return -1; 2381 } 2382 if (alt_path) 2383 path = alt_path; 2384 2385 yaffsfs_Lock(); 2386 parent = yaffsfs_FindDirectory(NULL, path, &name, 0, ¬Dir, &loop); 2387 if (!parent && notDir) 2388 yaffsfs_SetError(-ENOTDIR); 2389 else if (loop) 2390 yaffsfs_SetError(-ELOOP); 2391 else if (!parent) 2392 yaffsfs_SetError(-ENOENT); 2393 else if (yaffsfs_TooManyObjects(parent->my_dev)) 2394 yaffsfs_SetError(-ENFILE); 2395 else if (yaffs_strnlen(name, 5) == 0) { 2396 /* Trying to make the root itself */ 2397 yaffsfs_SetError(-EEXIST); 2398 } else if (parent->my_dev->read_only) 2399 yaffsfs_SetError(-EROFS); 2400 else { 2401 dir = yaffs_create_dir(parent, name, mode, 0, 0); 2402 if (dir) 2403 retVal = 0; 2404 else if (yaffs_find_by_name(parent, name)) 2405 yaffsfs_SetError(-EEXIST); /* name exists */ 2406 else 2407 yaffsfs_SetError(-ENOSPC); /* assume no space */ 2408 } 2409 2410 yaffsfs_Unlock(); 2411 2412 kfree(alt_path); 2413 2414 return retVal; 2415 } 2416 2417 int yaffs_rmdir(const YCHAR *path) 2418 { 2419 int result; 2420 YCHAR *alt_path; 2421 2422 if (!path) { 2423 yaffsfs_SetError(-EFAULT); 2424 return -1; 2425 } 2426 2427 if (yaffsfs_CheckPath(path) < 0) { 2428 yaffsfs_SetError(-ENAMETOOLONG); 2429 return -1; 2430 } 2431 2432 if (yaffsfs_alt_dir_path(path, &alt_path) < 0) { 2433 yaffsfs_SetError(-ENOMEM); 2434 return -1; 2435 } 2436 if (alt_path) 2437 path = alt_path; 2438 result = yaffsfs_DoUnlink(path, 1); 2439 2440 kfree(alt_path); 2441 2442 return result; 2443 } 2444 2445 void *yaffs_getdev(const YCHAR *path) 2446 { 2447 struct yaffs_dev *dev = NULL; 2448 YCHAR *dummy; 2449 dev = yaffsfs_FindDevice(path, &dummy); 2450 return (void *)dev; 2451 } 2452 2453 int yaffs_mount_common(const YCHAR *path, int read_only, int skip_checkpt) 2454 { 2455 int retVal = -1; 2456 int result = YAFFS_FAIL; 2457 struct yaffs_dev *dev = NULL; 2458 2459 if (!path) { 2460 yaffsfs_SetError(-EFAULT); 2461 return -1; 2462 } 2463 2464 yaffs_trace(YAFFS_TRACE_MOUNT, "yaffs: Mounting %s", path); 2465 2466 if (yaffsfs_CheckPath(path) < 0) { 2467 yaffsfs_SetError(-ENAMETOOLONG); 2468 return -1; 2469 } 2470 2471 yaffsfs_Lock(); 2472 2473 yaffsfs_InitHandles(); 2474 2475 dev = yaffsfs_FindMountPoint(path); 2476 if (dev) { 2477 if (!dev->is_mounted) { 2478 dev->read_only = read_only ? 1 : 0; 2479 if (skip_checkpt) { 2480 u8 skip = dev->param.skip_checkpt_rd; 2481 dev->param.skip_checkpt_rd = 1; 2482 result = yaffs_guts_initialise(dev); 2483 dev->param.skip_checkpt_rd = skip; 2484 } else { 2485 result = yaffs_guts_initialise(dev); 2486 } 2487 2488 if (result == YAFFS_FAIL) 2489 yaffsfs_SetError(-ENOMEM); 2490 retVal = result ? 0 : -1; 2491 2492 } else 2493 yaffsfs_SetError(-EBUSY); 2494 } else 2495 yaffsfs_SetError(-ENODEV); 2496 2497 yaffsfs_Unlock(); 2498 return retVal; 2499 2500 } 2501 2502 int yaffs_mount2(const YCHAR *path, int readonly) 2503 { 2504 return yaffs_mount_common(path, readonly, 0); 2505 } 2506 2507 int yaffs_mount(const YCHAR *path) 2508 { 2509 return yaffs_mount_common(path, 0, 0); 2510 } 2511 2512 int yaffs_sync(const YCHAR *path) 2513 { 2514 int retVal = -1; 2515 struct yaffs_dev *dev = NULL; 2516 YCHAR *dummy; 2517 2518 if (!path) { 2519 yaffsfs_SetError(-EFAULT); 2520 return -1; 2521 } 2522 2523 if (yaffsfs_CheckPath(path) < 0) { 2524 yaffsfs_SetError(-ENAMETOOLONG); 2525 return -1; 2526 } 2527 2528 yaffsfs_Lock(); 2529 dev = yaffsfs_FindDevice(path, &dummy); 2530 if (dev) { 2531 if (!dev->is_mounted) 2532 yaffsfs_SetError(-EINVAL); 2533 else if (dev->read_only) 2534 yaffsfs_SetError(-EROFS); 2535 else { 2536 2537 yaffs_flush_whole_cache(dev); 2538 yaffs_checkpoint_save(dev); 2539 retVal = 0; 2540 2541 } 2542 } else 2543 yaffsfs_SetError(-ENODEV); 2544 2545 yaffsfs_Unlock(); 2546 return retVal; 2547 } 2548 2549 static int yaffsfs_IsDevBusy(struct yaffs_dev *dev) 2550 { 2551 int i; 2552 struct yaffs_obj *obj; 2553 2554 for (i = 0; i < YAFFSFS_N_HANDLES; i++) { 2555 obj = yaffsfs_HandleToObject(i); 2556 if (obj && obj->my_dev == dev) 2557 return 1; 2558 } 2559 return 0; 2560 } 2561 2562 int yaffs_remount(const YCHAR *path, int force, int read_only) 2563 { 2564 int retVal = -1; 2565 struct yaffs_dev *dev = NULL; 2566 2567 if (!path) { 2568 yaffsfs_SetError(-EFAULT); 2569 return -1; 2570 } 2571 2572 if (yaffsfs_CheckPath(path) < 0) { 2573 yaffsfs_SetError(-ENAMETOOLONG); 2574 return -1; 2575 } 2576 2577 yaffsfs_Lock(); 2578 dev = yaffsfs_FindMountPoint(path); 2579 if (dev) { 2580 if (dev->is_mounted) { 2581 yaffs_flush_whole_cache(dev); 2582 2583 if (force || !yaffsfs_IsDevBusy(dev)) { 2584 if (read_only) 2585 yaffs_checkpoint_save(dev); 2586 dev->read_only = read_only ? 1 : 0; 2587 retVal = 0; 2588 } else 2589 yaffsfs_SetError(-EBUSY); 2590 2591 } else 2592 yaffsfs_SetError(-EINVAL); 2593 2594 } else 2595 yaffsfs_SetError(-ENODEV); 2596 2597 yaffsfs_Unlock(); 2598 return retVal; 2599 2600 } 2601 2602 int yaffs_unmount2(const YCHAR *path, int force) 2603 { 2604 int retVal = -1; 2605 struct yaffs_dev *dev = NULL; 2606 2607 if (!path) { 2608 yaffsfs_SetError(-EFAULT); 2609 return -1; 2610 } 2611 2612 if (yaffsfs_CheckPath(path) < 0) { 2613 yaffsfs_SetError(-ENAMETOOLONG); 2614 return -1; 2615 } 2616 2617 yaffsfs_Lock(); 2618 dev = yaffsfs_FindMountPoint(path); 2619 if (dev) { 2620 if (dev->is_mounted) { 2621 int inUse; 2622 yaffs_flush_whole_cache(dev); 2623 yaffs_checkpoint_save(dev); 2624 inUse = yaffsfs_IsDevBusy(dev); 2625 if (!inUse || force) { 2626 if (inUse) 2627 yaffsfs_BreakDeviceHandles(dev); 2628 yaffs_deinitialise(dev); 2629 2630 retVal = 0; 2631 } else 2632 yaffsfs_SetError(-EBUSY); 2633 2634 } else 2635 yaffsfs_SetError(-EINVAL); 2636 2637 } else 2638 yaffsfs_SetError(-ENODEV); 2639 2640 yaffsfs_Unlock(); 2641 return retVal; 2642 2643 } 2644 2645 int yaffs_unmount(const YCHAR *path) 2646 { 2647 return yaffs_unmount2(path, 0); 2648 } 2649 2650 loff_t yaffs_freespace(const YCHAR *path) 2651 { 2652 loff_t retVal = -1; 2653 struct yaffs_dev *dev = NULL; 2654 YCHAR *dummy; 2655 2656 if (!path) { 2657 yaffsfs_SetError(-EFAULT); 2658 return -1; 2659 } 2660 2661 if (yaffsfs_CheckPath(path) < 0) { 2662 yaffsfs_SetError(-ENAMETOOLONG); 2663 return -1; 2664 } 2665 2666 yaffsfs_Lock(); 2667 dev = yaffsfs_FindDevice(path, &dummy); 2668 if (dev && dev->is_mounted) { 2669 retVal = yaffs_get_n_free_chunks(dev); 2670 retVal *= dev->data_bytes_per_chunk; 2671 2672 } else 2673 yaffsfs_SetError(-EINVAL); 2674 2675 yaffsfs_Unlock(); 2676 return retVal; 2677 } 2678 2679 loff_t yaffs_totalspace(const YCHAR *path) 2680 { 2681 loff_t retVal = -1; 2682 struct yaffs_dev *dev = NULL; 2683 YCHAR *dummy; 2684 2685 if (!path) { 2686 yaffsfs_SetError(-EFAULT); 2687 return -1; 2688 } 2689 2690 if (yaffsfs_CheckPath(path) < 0) { 2691 yaffsfs_SetError(-ENAMETOOLONG); 2692 return -1; 2693 } 2694 2695 yaffsfs_Lock(); 2696 dev = yaffsfs_FindDevice(path, &dummy); 2697 if (dev && dev->is_mounted) { 2698 retVal = (dev->param.end_block - dev->param.start_block + 1) - 2699 dev->param.n_reserved_blocks; 2700 retVal *= dev->param.chunks_per_block; 2701 retVal *= dev->data_bytes_per_chunk; 2702 2703 } else 2704 yaffsfs_SetError(-EINVAL); 2705 2706 yaffsfs_Unlock(); 2707 return retVal; 2708 } 2709 2710 int yaffs_inodecount(const YCHAR *path) 2711 { 2712 loff_t retVal = -1; 2713 struct yaffs_dev *dev = NULL; 2714 YCHAR *dummy; 2715 2716 if (!path) { 2717 yaffsfs_SetError(-EFAULT); 2718 return -1; 2719 } 2720 2721 if (yaffsfs_CheckPath(path) < 0) { 2722 yaffsfs_SetError(-ENAMETOOLONG); 2723 return -1; 2724 } 2725 2726 yaffsfs_Lock(); 2727 dev = yaffsfs_FindDevice(path, &dummy); 2728 if (dev && dev->is_mounted) { 2729 int n_obj = dev->n_obj; 2730 if (n_obj > dev->n_hardlinks) 2731 retVal = n_obj - dev->n_hardlinks; 2732 } 2733 2734 if (retVal < 0) 2735 yaffsfs_SetError(-EINVAL); 2736 2737 yaffsfs_Unlock(); 2738 return retVal; 2739 } 2740 2741 void yaffs_add_device(struct yaffs_dev *dev) 2742 { 2743 struct list_head *cfg; 2744 /* First check that the device is not in the list. */ 2745 2746 list_for_each(cfg, &yaffsfs_deviceList) { 2747 if (dev == list_entry(cfg, struct yaffs_dev, dev_list)) 2748 return; 2749 } 2750 2751 dev->is_mounted = 0; 2752 dev->param.remove_obj_fn = yaffsfs_RemoveObjectCallback; 2753 2754 if (!dev->dev_list.next) 2755 INIT_LIST_HEAD(&dev->dev_list); 2756 2757 list_add(&dev->dev_list, &yaffsfs_deviceList); 2758 } 2759 2760 void yaffs_remove_device(struct yaffs_dev *dev) 2761 { 2762 list_del_init(&dev->dev_list); 2763 } 2764 2765 /* Functions to iterate through devices. NB Use with extreme care! */ 2766 2767 static struct list_head *dev_iterator; 2768 void yaffs_dev_rewind(void) 2769 { 2770 dev_iterator = yaffsfs_deviceList.next; 2771 } 2772 2773 struct yaffs_dev *yaffs_next_dev(void) 2774 { 2775 struct yaffs_dev *retval; 2776 2777 if (!dev_iterator) 2778 return NULL; 2779 if (dev_iterator == &yaffsfs_deviceList) 2780 return NULL; 2781 2782 retval = list_entry(dev_iterator, struct yaffs_dev, dev_list); 2783 dev_iterator = dev_iterator->next; 2784 return retval; 2785 } 2786 2787 /* Directory search stuff. */ 2788 2789 static struct list_head search_contexts; 2790 2791 static void yaffsfs_SetDirRewound(struct yaffsfs_DirSearchContxt *dsc) 2792 { 2793 if (dsc && 2794 dsc->dirObj && 2795 dsc->dirObj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) { 2796 2797 dsc->offset = 0; 2798 2799 if (list_empty(&dsc->dirObj->variant.dir_variant.children)) 2800 dsc->nextReturn = NULL; 2801 else 2802 dsc->nextReturn = 2803 list_entry(dsc->dirObj->variant.dir_variant. 2804 children.next, struct yaffs_obj, 2805 siblings); 2806 } else { 2807 /* Hey someone isn't playing nice! */ 2808 } 2809 } 2810 2811 static void yaffsfs_DirAdvance(struct yaffsfs_DirSearchContxt *dsc) 2812 { 2813 if (dsc && 2814 dsc->dirObj && 2815 dsc->dirObj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) { 2816 2817 if (dsc->nextReturn == NULL || 2818 list_empty(&dsc->dirObj->variant.dir_variant.children)) 2819 dsc->nextReturn = NULL; 2820 else { 2821 struct list_head *next = dsc->nextReturn->siblings.next; 2822 2823 if (next == &dsc->dirObj->variant.dir_variant.children) 2824 dsc->nextReturn = NULL; /* end of list */ 2825 else 2826 dsc->nextReturn = list_entry(next, 2827 struct yaffs_obj, 2828 siblings); 2829 } 2830 } else { 2831 /* Hey someone isn't playing nice! */ 2832 } 2833 } 2834 2835 static void yaffsfs_RemoveObjectCallback(struct yaffs_obj *obj) 2836 { 2837 2838 struct list_head *i; 2839 struct yaffsfs_DirSearchContxt *dsc; 2840 2841 /* if search contexts not initilised then skip */ 2842 if (!search_contexts.next) 2843 return; 2844 2845 /* Iterate through the directory search contexts. 2846 * If any are the one being removed, then advance the dsc to 2847 * the next one to prevent a hanging ptr. 2848 */ 2849 list_for_each(i, &search_contexts) { 2850 dsc = list_entry(i, struct yaffsfs_DirSearchContxt, others); 2851 if (dsc->nextReturn == obj) 2852 yaffsfs_DirAdvance(dsc); 2853 } 2854 2855 } 2856 2857 yaffs_DIR *yaffs_opendir(const YCHAR *dirname) 2858 { 2859 yaffs_DIR *dir = NULL; 2860 struct yaffs_obj *obj = NULL; 2861 struct yaffsfs_DirSearchContxt *dsc = NULL; 2862 int notDir = 0; 2863 int loop = 0; 2864 2865 if (!dirname) { 2866 yaffsfs_SetError(-EFAULT); 2867 return NULL; 2868 } 2869 2870 if (yaffsfs_CheckPath(dirname) < 0) { 2871 yaffsfs_SetError(-ENAMETOOLONG); 2872 return NULL; 2873 } 2874 2875 yaffsfs_Lock(); 2876 2877 obj = yaffsfs_FindObject(NULL, dirname, 0, 1, NULL, ¬Dir, &loop); 2878 2879 if (!obj && notDir) 2880 yaffsfs_SetError(-ENOTDIR); 2881 else if (loop) 2882 yaffsfs_SetError(-ELOOP); 2883 else if (!obj) 2884 yaffsfs_SetError(-ENOENT); 2885 else if (obj->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) 2886 yaffsfs_SetError(-ENOTDIR); 2887 else { 2888 int i; 2889 2890 for (i = 0, dsc = NULL; i < YAFFSFS_N_DSC && !dsc; i++) { 2891 if (!yaffsfs_dsc[i].inUse) 2892 dsc = &yaffsfs_dsc[i]; 2893 } 2894 2895 dir = (yaffs_DIR *) dsc; 2896 2897 if (dsc) { 2898 memset(dsc, 0, sizeof(struct yaffsfs_DirSearchContxt)); 2899 dsc->inUse = 1; 2900 dsc->dirObj = obj; 2901 yaffs_strncpy(dsc->name, dirname, NAME_MAX); 2902 INIT_LIST_HEAD(&dsc->others); 2903 2904 if (!search_contexts.next) 2905 INIT_LIST_HEAD(&search_contexts); 2906 2907 list_add(&dsc->others, &search_contexts); 2908 yaffsfs_SetDirRewound(dsc); 2909 } 2910 2911 } 2912 2913 yaffsfs_Unlock(); 2914 2915 return dir; 2916 } 2917 2918 struct yaffs_dirent *yaffs_readdir(yaffs_DIR * dirp) 2919 { 2920 struct yaffsfs_DirSearchContxt *dsc; 2921 struct yaffs_dirent *retVal = NULL; 2922 2923 dsc = (struct yaffsfs_DirSearchContxt *) dirp; 2924 yaffsfs_Lock(); 2925 2926 if (dsc && dsc->inUse) { 2927 yaffsfs_SetError(0); 2928 if (dsc->nextReturn) { 2929 dsc->de.d_ino = 2930 yaffs_get_equivalent_obj(dsc->nextReturn)->obj_id; 2931 dsc->de.d_dont_use = (unsigned)dsc->nextReturn; 2932 dsc->de.d_off = dsc->offset++; 2933 yaffs_get_obj_name(dsc->nextReturn, 2934 dsc->de.d_name, NAME_MAX); 2935 if (yaffs_strnlen(dsc->de.d_name, NAME_MAX + 1) == 0) { 2936 /* this should not happen! */ 2937 yaffs_strcpy(dsc->de.d_name, _Y("zz")); 2938 } 2939 dsc->de.d_reclen = sizeof(struct yaffs_dirent); 2940 retVal = &dsc->de; 2941 yaffsfs_DirAdvance(dsc); 2942 } else 2943 retVal = NULL; 2944 } else 2945 yaffsfs_SetError(-EBADF); 2946 2947 yaffsfs_Unlock(); 2948 2949 return retVal; 2950 2951 } 2952 2953 void yaffs_rewinddir(yaffs_DIR *dirp) 2954 { 2955 struct yaffsfs_DirSearchContxt *dsc; 2956 2957 dsc = (struct yaffsfs_DirSearchContxt *) dirp; 2958 2959 yaffsfs_Lock(); 2960 2961 yaffsfs_SetDirRewound(dsc); 2962 2963 yaffsfs_Unlock(); 2964 } 2965 2966 int yaffs_closedir(yaffs_DIR *dirp) 2967 { 2968 struct yaffsfs_DirSearchContxt *dsc; 2969 2970 dsc = (struct yaffsfs_DirSearchContxt *) dirp; 2971 2972 if (!dsc) { 2973 yaffsfs_SetError(-EFAULT); 2974 return -1; 2975 } 2976 2977 yaffsfs_Lock(); 2978 dsc->inUse = 0; 2979 list_del(&dsc->others); /* unhook from list */ 2980 yaffsfs_Unlock(); 2981 return 0; 2982 } 2983 2984 /* End of directory stuff */ 2985 2986 int yaffs_symlink(const YCHAR *oldpath, const YCHAR *newpath) 2987 { 2988 struct yaffs_obj *parent = NULL; 2989 struct yaffs_obj *obj; 2990 YCHAR *name; 2991 int retVal = -1; 2992 int mode = 0; /* ignore for now */ 2993 int notDir = 0; 2994 int loop = 0; 2995 2996 if (!oldpath || !newpath) { 2997 yaffsfs_SetError(-EFAULT); 2998 return -1; 2999 } 3000 3001 if (yaffsfs_CheckPath(newpath) < 0 || yaffsfs_CheckPath(oldpath) < 0) { 3002 yaffsfs_SetError(-ENAMETOOLONG); 3003 return -1; 3004 } 3005 3006 yaffsfs_Lock(); 3007 parent = yaffsfs_FindDirectory(NULL, newpath, &name, 0, ¬Dir, &loop); 3008 if (!parent && notDir) 3009 yaffsfs_SetError(-ENOTDIR); 3010 else if (loop) 3011 yaffsfs_SetError(-ELOOP); 3012 else if (!parent || yaffs_strnlen(name, 5) < 1) 3013 yaffsfs_SetError(-ENOENT); 3014 else if (yaffsfs_TooManyObjects(parent->my_dev)) 3015 yaffsfs_SetError(-ENFILE); 3016 else if (parent->my_dev->read_only) 3017 yaffsfs_SetError(-EROFS); 3018 else { 3019 obj = yaffs_create_symlink(parent, name, mode, 0, 0, oldpath); 3020 if (obj) 3021 retVal = 0; 3022 else if (yaffsfs_FindObject 3023 (NULL, newpath, 0, 0, NULL, NULL, NULL)) 3024 yaffsfs_SetError(-EEXIST); 3025 else 3026 yaffsfs_SetError(-ENOSPC); 3027 } 3028 3029 yaffsfs_Unlock(); 3030 3031 return retVal; 3032 3033 } 3034 3035 int yaffs_readlink(const YCHAR *path, YCHAR *buf, int bufsiz) 3036 { 3037 struct yaffs_obj *obj = NULL; 3038 struct yaffs_obj *dir = NULL; 3039 int retVal = -1; 3040 int notDir = 0; 3041 int loop = 0; 3042 3043 if (!path || !buf) { 3044 yaffsfs_SetError(-EFAULT); 3045 return -1; 3046 } 3047 3048 yaffsfs_Lock(); 3049 3050 obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, ¬Dir, &loop); 3051 3052 if (!dir && notDir) 3053 yaffsfs_SetError(-ENOTDIR); 3054 else if (loop) 3055 yaffsfs_SetError(-ELOOP); 3056 else if (!dir || !obj) 3057 yaffsfs_SetError(-ENOENT); 3058 else if (obj->variant_type != YAFFS_OBJECT_TYPE_SYMLINK) 3059 yaffsfs_SetError(-EINVAL); 3060 else { 3061 YCHAR *alias = obj->variant.symlink_variant.alias; 3062 memset(buf, 0, bufsiz); 3063 yaffs_strncpy(buf, alias, bufsiz - 1); 3064 retVal = 0; 3065 } 3066 yaffsfs_Unlock(); 3067 return retVal; 3068 } 3069 3070 int yaffs_link(const YCHAR *oldpath, const YCHAR *linkpath) 3071 { 3072 /* Creates a link called newpath to existing oldpath */ 3073 struct yaffs_obj *obj = NULL; 3074 struct yaffs_obj *lnk = NULL; 3075 struct yaffs_obj *obj_dir = NULL; 3076 struct yaffs_obj *lnk_dir = NULL; 3077 int retVal = -1; 3078 int notDirObj = 0; 3079 int notDirLnk = 0; 3080 int objLoop = 0; 3081 int lnkLoop = 0; 3082 YCHAR *newname; 3083 3084 if (!oldpath || !linkpath) { 3085 yaffsfs_SetError(-EFAULT); 3086 return -1; 3087 } 3088 3089 if (yaffsfs_CheckPath(linkpath) < 0 || yaffsfs_CheckPath(oldpath) < 0) { 3090 yaffsfs_SetError(-ENAMETOOLONG); 3091 return -1; 3092 } 3093 3094 yaffsfs_Lock(); 3095 3096 obj = yaffsfs_FindObject(NULL, oldpath, 0, 1, 3097 &obj_dir, ¬DirObj, &objLoop); 3098 lnk = yaffsfs_FindObject(NULL, linkpath, 0, 0, NULL, NULL, NULL); 3099 lnk_dir = yaffsfs_FindDirectory(NULL, linkpath, &newname, 3100 0, ¬DirLnk, &lnkLoop); 3101 3102 if ((!obj_dir && notDirObj) || (!lnk_dir && notDirLnk)) 3103 yaffsfs_SetError(-ENOTDIR); 3104 else if (objLoop || lnkLoop) 3105 yaffsfs_SetError(-ELOOP); 3106 else if (!obj_dir || !lnk_dir || !obj) 3107 yaffsfs_SetError(-ENOENT); 3108 else if (obj->my_dev->read_only) 3109 yaffsfs_SetError(-EROFS); 3110 else if (yaffsfs_TooManyObjects(obj->my_dev)) 3111 yaffsfs_SetError(-ENFILE); 3112 else if (lnk) 3113 yaffsfs_SetError(-EEXIST); 3114 else if (lnk_dir->my_dev != obj->my_dev) 3115 yaffsfs_SetError(-EXDEV); 3116 else { 3117 retVal = yaffsfs_CheckNameLength(newname); 3118 3119 if (retVal == 0) { 3120 lnk = yaffs_link_obj(lnk_dir, newname, obj); 3121 if (lnk) 3122 retVal = 0; 3123 else { 3124 yaffsfs_SetError(-ENOSPC); 3125 retVal = -1; 3126 } 3127 } 3128 } 3129 yaffsfs_Unlock(); 3130 3131 return retVal; 3132 } 3133 3134 int yaffs_mknod(const YCHAR *pathname, mode_t mode, dev_t dev) 3135 { 3136 yaffsfs_SetError(-EINVAL); 3137 return -1; 3138 } 3139 3140 /* 3141 * D E B U G F U N C T I O N S 3142 */ 3143 3144 /* 3145 * yaffs_n_handles() 3146 * Returns number of handles attached to the object 3147 */ 3148 int yaffs_n_handles(const YCHAR *path) 3149 { 3150 struct yaffs_obj *obj; 3151 3152 if (!path) { 3153 yaffsfs_SetError(-EFAULT); 3154 return -1; 3155 } 3156 3157 if (yaffsfs_CheckPath(path) < 0) { 3158 yaffsfs_SetError(-ENAMETOOLONG); 3159 return -1; 3160 } 3161 3162 obj = yaffsfs_FindObject(NULL, path, 0, 1, NULL, NULL, NULL); 3163 3164 if (obj) 3165 return yaffsfs_CountHandles(obj); 3166 else 3167 return -1; 3168 } 3169 3170 int yaffs_get_error(void) 3171 { 3172 return yaffsfs_GetLastError(); 3173 } 3174 3175 int yaffs_set_error(int error) 3176 { 3177 yaffsfs_SetError(error); 3178 return 0; 3179 } 3180 3181 int yaffs_dump_dev(const YCHAR *path) 3182 { 3183 #if 0 3184 YCHAR *rest; 3185 3186 struct yaffs_obj *obj = yaffsfs_FindRoot(path, &rest); 3187 3188 if (obj) { 3189 struct yaffs_dev *dev = obj->my_dev; 3190 3191 printf("\n" 3192 "n_page_writes.......... %d\n" 3193 "n_page_reads........... %d\n" 3194 "n_erasures....... %d\n" 3195 "n_gc_copies............ %d\n" 3196 "garbageCollections... %d\n" 3197 "passiveGarbageColl'ns %d\n" 3198 "\n", 3199 dev->n_page_writes, 3200 dev->n_page_reads, 3201 dev->n_erasures, 3202 dev->n_gc_copies, 3203 dev->garbageCollections, dev->passiveGarbageCollections); 3204 3205 } 3206 #endif 3207 return 0; 3208 } 3209