OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [fs/] [seq_file.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * linux/fs/seq_file.c
3
 *
4
 * helper functions for making synthetic files from sequences of records.
5
 * initial implementation -- AV, Oct 2001.
6
 */
7
 
8
#include <linux/fs.h>
9
#include <linux/seq_file.h>
10
#include <linux/slab.h>
11
 
12
#include <asm/uaccess.h>
13
#include <asm/page.h>
14
 
15
/**
16
 *      seq_open -      initialize sequential file
17
 *      @file: file we initialize
18
 *      @op: method table describing the sequence
19
 *
20
 *      seq_open() sets @file, associating it with a sequence described
21
 *      by @op.  @op->start() sets the iterator up and returns the first
22
 *      element of sequence. @op->stop() shuts it down.  @op->next()
23
 *      returns the next element of sequence.  @op->show() prints element
24
 *      into the buffer.  In case of error ->start() and ->next() return
25
 *      ERR_PTR(error).  In the end of sequence they return %NULL. ->show()
26
 *      returns 0 in case of success and negative number in case of error.
27
 */
28
int seq_open(struct file *file, struct seq_operations *op)
29
{
30
        struct seq_file *p = kmalloc(sizeof(*p), GFP_KERNEL);
31
        if (!p)
32
                return -ENOMEM;
33
        memset(p, 0, sizeof(*p));
34
        sema_init(&p->sem, 1);
35
        p->op = op;
36
        file->private_data = p;
37
        return 0;
38
}
39
 
40
/**
41
 *      seq_read -      ->read() method for sequential files.
42
 *      @file, @buf, @size, @ppos: see file_operations method
43
 *
44
 *      Ready-made ->f_op->read()
45
 */
46
ssize_t seq_read(struct file *file, char *buf, size_t size, loff_t *ppos)
47
{
48
        struct seq_file *m = (struct seq_file *)file->private_data;
49
        size_t copied = 0;
50
        loff_t pos;
51
        size_t n;
52
        void *p;
53
        int err = 0;
54
 
55
        if (ppos != &file->f_pos)
56
                return -EPIPE;
57
 
58
        down(&m->sem);
59
        /* grab buffer if we didn't have one */
60
        if (!m->buf) {
61
                m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL);
62
                if (!m->buf)
63
                        goto Enomem;
64
        }
65
        /* if not empty - flush it first */
66
        if (m->count) {
67
                n = min(m->count, size);
68
                err = copy_to_user(buf, m->buf + m->from, n);
69
                if (err)
70
                        goto Efault;
71
                m->count -= n;
72
                m->from += n;
73
                size -= n;
74
                buf += n;
75
                copied += n;
76
                if (!m->count)
77
                        m->index++;
78
                if (!size)
79
                        goto Done;
80
        }
81
        /* we need at least one record in buffer */
82
        while (1) {
83
                pos = m->index;
84
                p = m->op->start(m, &pos);
85
                err = PTR_ERR(p);
86
                if (!p || IS_ERR(p))
87
                        break;
88
                err = m->op->show(m, p);
89
                if (err)
90
                        break;
91
                if (m->count < m->size)
92
                        goto Fill;
93
                m->op->stop(m, p);
94
                kfree(m->buf);
95
                m->buf = kmalloc(m->size <<= 1, GFP_KERNEL);
96
                if (!m->buf)
97
                        goto Enomem;
98
                m->count = 0;
99
        }
100
        m->op->stop(m, p);
101
        m->count = 0;
102
        goto Done;
103
Fill:
104
        /* they want more? let's try to get some more */
105
        while (m->count < size) {
106
                size_t offs = m->count;
107
                loff_t next = pos;
108
                p = m->op->next(m, p, &next);
109
                if (!p || IS_ERR(p)) {
110
                        err = PTR_ERR(p);
111
                        break;
112
                }
113
                err = m->op->show(m, p);
114
                if (err || m->count == m->size) {
115
                        m->count = offs;
116
                        break;
117
                }
118
                pos = next;
119
        }
120
        m->op->stop(m, p);
121
        n = min(m->count, size);
122
        err = copy_to_user(buf, m->buf, n);
123
        if (err)
124
                goto Efault;
125
        copied += n;
126
        m->count -= n;
127
        if (m->count)
128
                m->from = n;
129
        else
130
                pos++;
131
        m->index = pos;
132
Done:
133
        if (!copied)
134
                copied = err;
135
        else
136
                *ppos += copied;
137
        up(&m->sem);
138
        return copied;
139
Enomem:
140
        err = -ENOMEM;
141
        goto Done;
142
Efault:
143
        err = -EFAULT;
144
        goto Done;
145
}
146
 
147
static int traverse(struct seq_file *m, loff_t offset)
148
{
149
        loff_t pos = 0;
150
        int error = 0;
151
        void *p;
152
 
153
        m->index = 0;
154
        m->count = m->from = 0;
155
        if (!offset)
156
                return 0;
157
        if (!m->buf) {
158
                m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL);
159
                if (!m->buf)
160
                        return -ENOMEM;
161
        }
162
        p = m->op->start(m, &m->index);
163
        while (p) {
164
                error = PTR_ERR(p);
165
                if (IS_ERR(p))
166
                        break;
167
                error = m->op->show(m, p);
168
                if (error)
169
                        break;
170
                if (m->count == m->size)
171
                        goto Eoverflow;
172
                if (pos + m->count > offset) {
173
                        m->from = offset - pos;
174
                        m->count -= m->from;
175
                        break;
176
                }
177
                pos += m->count;
178
                m->count = 0;
179
                if (pos == offset) {
180
                        m->index++;
181
                        break;
182
                }
183
                p = m->op->next(m, p, &m->index);
184
        }
185
        m->op->stop(m, p);
186
        return error;
187
 
188
Eoverflow:
189
        m->op->stop(m, p);
190
        kfree(m->buf);
191
        m->buf = kmalloc(m->size <<= 1, GFP_KERNEL);
192
        return !m->buf ? -ENOMEM : -EAGAIN;
193
}
194
 
195
/**
196
 *      seq_lseek -     ->llseek() method for sequential files.
197
 *      @file, @offset, @origin: see file_operations method
198
 *
199
 *      Ready-made ->f_op->llseek()
200
 */
201
loff_t seq_lseek(struct file *file, loff_t offset, int origin)
202
{
203
        struct seq_file *m = (struct seq_file *)file->private_data;
204
        long long retval = -EINVAL;
205
 
206
        down(&m->sem);
207
        switch (origin) {
208
                case 1:
209
                        offset += file->f_pos;
210
                case 0:
211
                        if (offset < 0)
212
                                break;
213
                        retval = offset;
214
                        if (offset != file->f_pos) {
215
                                while ((retval=traverse(m, offset)) == -EAGAIN)
216
                                        ;
217
                                if (retval) {
218
                                        /* with extreme prejudice... */
219
                                        file->f_pos = 0;
220
                                        m->index = 0;
221
                                        m->count = 0;
222
                                } else {
223
                                        retval = file->f_pos = offset;
224
                                }
225
                        }
226
        }
227
        up(&m->sem);
228
        return retval;
229
}
230
 
231
/**
232
 *      seq_release -   free the structures associated with sequential file.
233
 *      @file: file in question
234
 *      @inode: file->f_dentry->d_inode
235
 *
236
 *      Frees the structures associated with sequential file; can be used
237
 *      as ->f_op->release() if you don't have private data to destroy.
238
 */
239
int seq_release(struct inode *inode, struct file *file)
240
{
241
        struct seq_file *m = (struct seq_file *)file->private_data;
242
        kfree(m->buf);
243
        kfree(m);
244
        return 0;
245
}
246
 
247
/**
248
 *      seq_escape -    print string into buffer, escaping some characters
249
 *      @m:     target buffer
250
 *      @s:     string
251
 *      @esc:   set of characters that need escaping
252
 *
253
 *      Puts string into buffer, replacing each occurrence of character from
254
 *      @esc with usual octal escape.  Returns 0 in case of success, -1 - in
255
 *      case of overflow.
256
 */
257
int seq_escape(struct seq_file *m, const char *s, const char *esc)
258
{
259
        char *end = m->buf + m->size;
260
        char *p;
261
        char c;
262
 
263
        for (p = m->buf + m->count; (c = *s) != '\0' && p < end; s++) {
264
                if (!strchr(esc, c)) {
265
                        *p++ = c;
266
                        continue;
267
                }
268
                if (p + 3 < end) {
269
                        *p++ = '\\';
270
                        *p++ = '0' + ((c & 0300) >> 6);
271
                        *p++ = '0' + ((c & 070) >> 3);
272
                        *p++ = '0' + (c & 07);
273
                        continue;
274
                }
275
                m->count = m->size;
276
                return -1;
277
        }
278
        m->count = p - m->buf;
279
        return 0;
280
}
281
 
282
int seq_printf(struct seq_file *m, const char *f, ...)
283
{
284
        va_list args;
285
        int len;
286
 
287
        if (m->count < m->size) {
288
                va_start(args, f);
289
                len = vsnprintf(m->buf + m->count, m->size - m->count, f, args);
290
                va_end(args);
291
                if (m->count + len < m->size) {
292
                        m->count += len;
293
                        return 0;
294
                }
295
        }
296
        m->count = m->size;
297
        return -1;
298
}
299
 
300
int seq_path(struct seq_file *m,
301
                struct vfsmount *mnt, struct dentry *dentry,
302
                char *esc)
303
{
304
        if (m->count < m->size) {
305
                char *s = m->buf + m->count;
306
                char *p = d_path(dentry, mnt, s, m->size - m->count);
307
                if (!IS_ERR(p)) {
308
                        while (s <= p) {
309
                                char c = *p++;
310
                                if (!c) {
311
                                        p = m->buf + m->count;
312
                                        m->count = s - m->buf;
313
                                        return s - p;
314
                                } else if (!strchr(esc, c)) {
315
                                        *s++ = c;
316
                                } else if (s + 4 > p) {
317
                                        break;
318
                                } else {
319
                                        *s++ = '\\';
320
                                        *s++ = '0' + ((c & 0300) >> 6);
321
                                        *s++ = '0' + ((c & 070) >> 3);
322
                                        *s++ = '0' + (c & 07);
323
                                }
324
                        }
325
                }
326
        }
327
        m->count = m->size;
328
        return -1;
329
}
330
 
331
static void *single_start(struct seq_file *p, loff_t *pos)
332
{
333
        return NULL + (*pos == 0);
334
}
335
 
336
static void *single_next(struct seq_file *p, void *v, loff_t *pos)
337
{
338
        ++*pos;
339
        return NULL;
340
}
341
 
342
static void single_stop(struct seq_file *p, void *v)
343
{
344
}
345
 
346
int single_open(struct file *file, int (*show)(struct seq_file *, void*), void *data)
347
{
348
        struct seq_operations *op = kmalloc(sizeof(*op), GFP_KERNEL);
349
        int res = -ENOMEM;
350
 
351
        if (op) {
352
                op->start = single_start;
353
                op->next = single_next;
354
                op->stop = single_stop;
355
                op->show = show;
356
                res = seq_open(file, op);
357
                if (!res)
358
                        ((struct seq_file *)file->private_data)->private = data;
359
                else
360
                        kfree(op);
361
        }
362
        return res;
363
}
364
 
365
int single_release(struct inode *inode, struct file *file)
366
{
367
        struct seq_operations *op = ((struct seq_file *)file->private_data)->op;
368
        int res = seq_release(inode, file);
369
        kfree(op);
370
        return res;
371
}
372
 
373
int seq_release_private(struct inode *inode, struct file *file)
374
{
375
        struct seq_file *seq = file->private_data;
376
 
377
        kfree(seq->private);
378
        seq->private = NULL;
379
        return seq_release(inode, file);
380
}
381
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.