uboot/fs/yaffs2/yaffs_nameval.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/*
  15 * This simple implementation of a name-value store assumes a small number of
  16* values and fits into a small finite buffer.
  17 *
  18 * Each attribute is stored as a record:
  19 *  sizeof(int) bytes   record size.
  20 *  yaffs_strnlen+1 bytes name null terminated.
  21 *  nbytes    value.
  22 *  ----------
  23 *  total size  stored in record size
  24 *
  25 * This code has not been tested with unicode yet.
  26 */
  27
  28#include "yaffs_nameval.h"
  29
  30#include "yportenv.h"
  31
  32static int nval_find(const char *xb, int xb_size, const YCHAR *name,
  33                     int *exist_size)
  34{
  35        int pos = 0;
  36        int size;
  37
  38        memcpy(&size, xb, sizeof(int));
  39        while (size > 0 && (size < xb_size) && (pos + size < xb_size)) {
  40                if (!yaffs_strncmp((YCHAR *) (xb + pos + sizeof(int)),
  41                                name, size)) {
  42                        if (exist_size)
  43                                *exist_size = size;
  44                        return pos;
  45                }
  46                pos += size;
  47                if (pos < xb_size - sizeof(int))
  48                        memcpy(&size, xb + pos, sizeof(int));
  49                else
  50                        size = 0;
  51        }
  52        if (exist_size)
  53                *exist_size = 0;
  54        return -ENODATA;
  55}
  56
  57static int nval_used(const char *xb, int xb_size)
  58{
  59        int pos = 0;
  60        int size;
  61
  62        memcpy(&size, xb + pos, sizeof(int));
  63        while (size > 0 && (size < xb_size) && (pos + size < xb_size)) {
  64                pos += size;
  65                if (pos < xb_size - sizeof(int))
  66                        memcpy(&size, xb + pos, sizeof(int));
  67                else
  68                        size = 0;
  69        }
  70        return pos;
  71}
  72
  73int nval_del(char *xb, int xb_size, const YCHAR *name)
  74{
  75        int pos = nval_find(xb, xb_size, name, NULL);
  76        int size;
  77
  78        if (pos < 0 || pos >= xb_size)
  79                return -ENODATA;
  80
  81        /* Find size, shift rest over this record,
  82         * then zero out the rest of buffer */
  83        memcpy(&size, xb + pos, sizeof(int));
  84        memcpy(xb + pos, xb + pos + size, xb_size - (pos + size));
  85        memset(xb + (xb_size - size), 0, size);
  86        return 0;
  87}
  88
  89int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf,
  90                int bsize, int flags)
  91{
  92        int pos;
  93        int namelen = yaffs_strnlen(name, xb_size);
  94        int reclen;
  95        int size_exist = 0;
  96        int space;
  97        int start;
  98
  99        pos = nval_find(xb, xb_size, name, &size_exist);
 100
 101        if (flags & XATTR_CREATE && pos >= 0)
 102                return -EEXIST;
 103        if (flags & XATTR_REPLACE && pos < 0)
 104                return -ENODATA;
 105
 106        start = nval_used(xb, xb_size);
 107        space = xb_size - start + size_exist;
 108
 109        reclen = (sizeof(int) + namelen + 1 + bsize);
 110
 111        if (reclen > space)
 112                return -ENOSPC;
 113
 114        if (pos >= 0) {
 115                nval_del(xb, xb_size, name);
 116                start = nval_used(xb, xb_size);
 117        }
 118
 119        pos = start;
 120
 121        memcpy(xb + pos, &reclen, sizeof(int));
 122        pos += sizeof(int);
 123        yaffs_strncpy((YCHAR *) (xb + pos), name, reclen);
 124        pos += (namelen + 1);
 125        memcpy(xb + pos, buf, bsize);
 126        return 0;
 127}
 128
 129int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf,
 130             int bsize)
 131{
 132        int pos = nval_find(xb, xb_size, name, NULL);
 133        int size;
 134
 135        if (pos >= 0 && pos < xb_size) {
 136
 137                memcpy(&size, xb + pos, sizeof(int));
 138                pos += sizeof(int);     /* advance past record length */
 139                size -= sizeof(int);
 140
 141                /* Advance over name string */
 142                while (xb[pos] && size > 0 && pos < xb_size) {
 143                        pos++;
 144                        size--;
 145                }
 146                /*Advance over NUL */
 147                pos++;
 148                size--;
 149
 150                /* If bsize is zero then this is a size query.
 151                 * Return the size, but don't copy.
 152                 */
 153                if (!bsize)
 154                        return size;
 155
 156                if (size <= bsize) {
 157                        memcpy(buf, xb + pos, size);
 158                        return size;
 159                }
 160        }
 161        if (pos >= 0)
 162                return -ERANGE;
 163
 164        return -ENODATA;
 165}
 166
 167int nval_list(const char *xb, int xb_size, char *buf, int bsize)
 168{
 169        int pos = 0;
 170        int size;
 171        int name_len;
 172        int ncopied = 0;
 173        int filled = 0;
 174
 175        memcpy(&size, xb + pos, sizeof(int));
 176        while (size > sizeof(int) &&
 177                size <= xb_size &&
 178                (pos + size) < xb_size &&
 179                !filled) {
 180                pos += sizeof(int);
 181                size -= sizeof(int);
 182                name_len = yaffs_strnlen((YCHAR *) (xb + pos), size);
 183                if (ncopied + name_len + 1 < bsize) {
 184                        memcpy(buf, xb + pos, name_len * sizeof(YCHAR));
 185                        buf += name_len;
 186                        *buf = '\0';
 187                        buf++;
 188                        if (sizeof(YCHAR) > 1) {
 189                                *buf = '\0';
 190                                buf++;
 191                        }
 192                        ncopied += (name_len + 1);
 193                } else {
 194                        filled = 1;
 195                }
 196                pos += size;
 197                if (pos < xb_size - sizeof(int))
 198                        memcpy(&size, xb + pos, sizeof(int));
 199                else
 200                        size = 0;
 201        }
 202        return ncopied;
 203}
 204
 205int nval_hasvalues(const char *xb, int xb_size)
 206{
 207        return nval_used(xb, xb_size) > 0;
 208}
 209