~ubuntu-branches/ubuntu/lucid/linux-rt/lucid

« back to all changes in this revision

Viewing changes to fs/romfs/storage.c

  • Committer: Bazaar Package Importer
  • Author(s): Luke Yelavich
  • Date: 2009-08-05 23:00:52 UTC
  • Revision ID: james.westby@ubuntu.com-20090805230052-7xedvqcyk9dnnxb2
Tags: 2.6.31-1.1
New upstream release

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* RomFS storage access routines
 
2
 *
 
3
 * Copyright © 2007 Red Hat, Inc. All Rights Reserved.
 
4
 * Written by David Howells (dhowells@redhat.com)
 
5
 *
 
6
 * This program is free software; you can redistribute it and/or
 
7
 * modify it under the terms of the GNU General Public License
 
8
 * as published by the Free Software Foundation; either version
 
9
 * 2 of the License, or (at your option) any later version.
 
10
 */
 
11
 
 
12
#include <linux/fs.h>
 
13
#include <linux/mtd/super.h>
 
14
#include <linux/buffer_head.h>
 
15
#include "internal.h"
 
16
 
 
17
#if !defined(CONFIG_ROMFS_ON_MTD) && !defined(CONFIG_ROMFS_ON_BLOCK)
 
18
#error no ROMFS backing store interface configured
 
19
#endif
 
20
 
 
21
#ifdef CONFIG_ROMFS_ON_MTD
 
22
#define ROMFS_MTD_READ(sb, ...) ((sb)->s_mtd->read((sb)->s_mtd, ##__VA_ARGS__))
 
23
 
 
24
/*
 
25
 * read data from an romfs image on an MTD device
 
26
 */
 
27
static int romfs_mtd_read(struct super_block *sb, unsigned long pos,
 
28
                          void *buf, size_t buflen)
 
29
{
 
30
        size_t rlen;
 
31
        int ret;
 
32
 
 
33
        ret = ROMFS_MTD_READ(sb, pos, buflen, &rlen, buf);
 
34
        return (ret < 0 || rlen != buflen) ? -EIO : 0;
 
35
}
 
36
 
 
37
/*
 
38
 * determine the length of a string in a romfs image on an MTD device
 
39
 */
 
40
static ssize_t romfs_mtd_strnlen(struct super_block *sb,
 
41
                                 unsigned long pos, size_t maxlen)
 
42
{
 
43
        ssize_t n = 0;
 
44
        size_t segment;
 
45
        u_char buf[16], *p;
 
46
        size_t len;
 
47
        int ret;
 
48
 
 
49
        /* scan the string up to 16 bytes at a time */
 
50
        while (maxlen > 0) {
 
51
                segment = min_t(size_t, maxlen, 16);
 
52
                ret = ROMFS_MTD_READ(sb, pos, segment, &len, buf);
 
53
                if (ret < 0)
 
54
                        return ret;
 
55
                p = memchr(buf, 0, len);
 
56
                if (p)
 
57
                        return n + (p - buf);
 
58
                maxlen -= len;
 
59
                pos += len;
 
60
                n += len;
 
61
        }
 
62
 
 
63
        return n;
 
64
}
 
65
 
 
66
/*
 
67
 * compare a string to one in a romfs image on MTD
 
68
 * - return 1 if matched, 0 if differ, -ve if error
 
69
 */
 
70
static int romfs_mtd_strcmp(struct super_block *sb, unsigned long pos,
 
71
                            const char *str, size_t size)
 
72
{
 
73
        u_char buf[17];
 
74
        size_t len, segment;
 
75
        int ret;
 
76
 
 
77
        /* scan the string up to 16 bytes at a time, and attempt to grab the
 
78
         * trailing NUL whilst we're at it */
 
79
        buf[0] = 0xff;
 
80
 
 
81
        while (size > 0) {
 
82
                segment = min_t(size_t, size + 1, 17);
 
83
                ret = ROMFS_MTD_READ(sb, pos, segment, &len, buf);
 
84
                if (ret < 0)
 
85
                        return ret;
 
86
                len--;
 
87
                if (memcmp(buf, str, len) != 0)
 
88
                        return 0;
 
89
                buf[0] = buf[len];
 
90
                size -= len;
 
91
                pos += len;
 
92
                str += len;
 
93
        }
 
94
 
 
95
        /* check the trailing NUL was */
 
96
        if (buf[0])
 
97
                return 0;
 
98
 
 
99
        return 1;
 
100
}
 
101
#endif /* CONFIG_ROMFS_ON_MTD */
 
102
 
 
103
#ifdef CONFIG_ROMFS_ON_BLOCK
 
104
/*
 
105
 * read data from an romfs image on a block device
 
106
 */
 
107
static int romfs_blk_read(struct super_block *sb, unsigned long pos,
 
108
                          void *buf, size_t buflen)
 
109
{
 
110
        struct buffer_head *bh;
 
111
        unsigned long offset;
 
112
        size_t segment;
 
113
 
 
114
        /* copy the string up to blocksize bytes at a time */
 
115
        while (buflen > 0) {
 
116
                offset = pos & (ROMBSIZE - 1);
 
117
                segment = min_t(size_t, buflen, ROMBSIZE - offset);
 
118
                bh = sb_bread(sb, pos >> ROMBSBITS);
 
119
                if (!bh)
 
120
                        return -EIO;
 
121
                memcpy(buf, bh->b_data + offset, segment);
 
122
                brelse(bh);
 
123
                buf += segment;
 
124
                buflen -= segment;
 
125
                pos += segment;
 
126
        }
 
127
 
 
128
        return 0;
 
129
}
 
130
 
 
131
/*
 
132
 * determine the length of a string in romfs on a block device
 
133
 */
 
134
static ssize_t romfs_blk_strnlen(struct super_block *sb,
 
135
                                 unsigned long pos, size_t limit)
 
136
{
 
137
        struct buffer_head *bh;
 
138
        unsigned long offset;
 
139
        ssize_t n = 0;
 
140
        size_t segment;
 
141
        u_char *buf, *p;
 
142
 
 
143
        /* scan the string up to blocksize bytes at a time */
 
144
        while (limit > 0) {
 
145
                offset = pos & (ROMBSIZE - 1);
 
146
                segment = min_t(size_t, limit, ROMBSIZE - offset);
 
147
                bh = sb_bread(sb, pos >> ROMBSBITS);
 
148
                if (!bh)
 
149
                        return -EIO;
 
150
                buf = bh->b_data + offset;
 
151
                p = memchr(buf, 0, segment);
 
152
                brelse(bh);
 
153
                if (p)
 
154
                        return n + (p - buf);
 
155
                limit -= segment;
 
156
                pos += segment;
 
157
                n += segment;
 
158
        }
 
159
 
 
160
        return n;
 
161
}
 
162
 
 
163
/*
 
164
 * compare a string to one in a romfs image on a block device
 
165
 * - return 1 if matched, 0 if differ, -ve if error
 
166
 */
 
167
static int romfs_blk_strcmp(struct super_block *sb, unsigned long pos,
 
168
                            const char *str, size_t size)
 
169
{
 
170
        struct buffer_head *bh;
 
171
        unsigned long offset;
 
172
        size_t segment;
 
173
        bool matched, terminated = false;
 
174
 
 
175
        /* compare string up to a block at a time */
 
176
        while (size > 0) {
 
177
                offset = pos & (ROMBSIZE - 1);
 
178
                segment = min_t(size_t, size, ROMBSIZE - offset);
 
179
                bh = sb_bread(sb, pos >> ROMBSBITS);
 
180
                if (!bh)
 
181
                        return -EIO;
 
182
                matched = (memcmp(bh->b_data + offset, str, segment) == 0);
 
183
 
 
184
                size -= segment;
 
185
                pos += segment;
 
186
                str += segment;
 
187
                if (matched && size == 0 && offset + segment < ROMBSIZE) {
 
188
                        if (!bh->b_data[offset + segment])
 
189
                                terminated = true;
 
190
                        else
 
191
                                matched = false;
 
192
                }
 
193
                brelse(bh);
 
194
                if (!matched)
 
195
                        return 0;
 
196
        }
 
197
 
 
198
        if (!terminated) {
 
199
                /* the terminating NUL must be on the first byte of the next
 
200
                 * block */
 
201
                BUG_ON((pos & (ROMBSIZE - 1)) != 0);
 
202
                bh = sb_bread(sb, pos >> ROMBSBITS);
 
203
                if (!bh)
 
204
                        return -EIO;
 
205
                matched = !bh->b_data[0];
 
206
                brelse(bh);
 
207
                if (!matched)
 
208
                        return 0;
 
209
        }
 
210
 
 
211
        return 1;
 
212
}
 
213
#endif /* CONFIG_ROMFS_ON_BLOCK */
 
214
 
 
215
/*
 
216
 * read data from the romfs image
 
217
 */
 
218
int romfs_dev_read(struct super_block *sb, unsigned long pos,
 
219
                   void *buf, size_t buflen)
 
220
{
 
221
        size_t limit;
 
222
 
 
223
        limit = romfs_maxsize(sb);
 
224
        if (pos >= limit)
 
225
                return -EIO;
 
226
        if (buflen > limit - pos)
 
227
                buflen = limit - pos;
 
228
 
 
229
#ifdef CONFIG_ROMFS_ON_MTD
 
230
        if (sb->s_mtd)
 
231
                return romfs_mtd_read(sb, pos, buf, buflen);
 
232
#endif
 
233
#ifdef CONFIG_ROMFS_ON_BLOCK
 
234
        if (sb->s_bdev)
 
235
                return romfs_blk_read(sb, pos, buf, buflen);
 
236
#endif
 
237
        return -EIO;
 
238
}
 
239
 
 
240
/*
 
241
 * determine the length of a string in romfs
 
242
 */
 
243
ssize_t romfs_dev_strnlen(struct super_block *sb,
 
244
                          unsigned long pos, size_t maxlen)
 
245
{
 
246
        size_t limit;
 
247
 
 
248
        limit = romfs_maxsize(sb);
 
249
        if (pos >= limit)
 
250
                return -EIO;
 
251
        if (maxlen > limit - pos)
 
252
                maxlen = limit - pos;
 
253
 
 
254
#ifdef CONFIG_ROMFS_ON_MTD
 
255
        if (sb->s_mtd)
 
256
                return romfs_mtd_strnlen(sb, pos, limit);
 
257
#endif
 
258
#ifdef CONFIG_ROMFS_ON_BLOCK
 
259
        if (sb->s_bdev)
 
260
                return romfs_blk_strnlen(sb, pos, limit);
 
261
#endif
 
262
        return -EIO;
 
263
}
 
264
 
 
265
/*
 
266
 * compare a string to one in romfs
 
267
 * - the string to be compared to, str, may not be NUL-terminated; instead the
 
268
 *   string is of the specified size
 
269
 * - return 1 if matched, 0 if differ, -ve if error
 
270
 */
 
271
int romfs_dev_strcmp(struct super_block *sb, unsigned long pos,
 
272
                     const char *str, size_t size)
 
273
{
 
274
        size_t limit;
 
275
 
 
276
        limit = romfs_maxsize(sb);
 
277
        if (pos >= limit)
 
278
                return -EIO;
 
279
        if (size > ROMFS_MAXFN)
 
280
                return -ENAMETOOLONG;
 
281
        if (size + 1 > limit - pos)
 
282
                return -EIO;
 
283
 
 
284
#ifdef CONFIG_ROMFS_ON_MTD
 
285
        if (sb->s_mtd)
 
286
                return romfs_mtd_strcmp(sb, pos, str, size);
 
287
#endif
 
288
#ifdef CONFIG_ROMFS_ON_BLOCK
 
289
        if (sb->s_bdev)
 
290
                return romfs_blk_strcmp(sb, pos, str, size);
 
291
#endif
 
292
        return -EIO;
 
293
}