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