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

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [fs/] [seq_file.c] - Blame information for rev 65

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
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/module.h>
10
#include <linux/seq_file.h>
11
#include <linux/slab.h>
12
 
13
#include <asm/uaccess.h>
14
#include <asm/page.h>
15
 
16
/**
17
 *      seq_open -      initialize sequential file
18
 *      @file: file we initialize
19
 *      @op: method table describing the sequence
20
 *
21
 *      seq_open() sets @file, associating it with a sequence described
22
 *      by @op.  @op->start() sets the iterator up and returns the first
23
 *      element of sequence. @op->stop() shuts it down.  @op->next()
24
 *      returns the next element of sequence.  @op->show() prints element
25
 *      into the buffer.  In case of error ->start() and ->next() return
26
 *      ERR_PTR(error).  In the end of sequence they return %NULL. ->show()
27
 *      returns 0 in case of success and negative number in case of error.
28
 */
29
int seq_open(struct file *file, const struct seq_operations *op)
30
{
31
        struct seq_file *p = file->private_data;
32
 
33
        if (!p) {
34
                p = kmalloc(sizeof(*p), GFP_KERNEL);
35
                if (!p)
36
                        return -ENOMEM;
37
                file->private_data = p;
38
        }
39
        memset(p, 0, sizeof(*p));
40
        mutex_init(&p->lock);
41
        p->op = op;
42
 
43
        /*
44
         * Wrappers around seq_open(e.g. swaps_open) need to be
45
         * aware of this. If they set f_version themselves, they
46
         * should call seq_open first and then set f_version.
47
         */
48
        file->f_version = 0;
49
 
50
        /* SEQ files support lseek, but not pread/pwrite */
51
        file->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE);
52
        return 0;
53
}
54
EXPORT_SYMBOL(seq_open);
55
 
56
/**
57
 *      seq_read -      ->read() method for sequential files.
58
 *      @file: the file to read from
59
 *      @buf: the buffer to read to
60
 *      @size: the maximum number of bytes to read
61
 *      @ppos: the current position in the file
62
 *
63
 *      Ready-made ->f_op->read()
64
 */
65
ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
66
{
67
        struct seq_file *m = (struct seq_file *)file->private_data;
68
        size_t copied = 0;
69
        loff_t pos;
70
        size_t n;
71
        void *p;
72
        int err = 0;
73
 
74
        mutex_lock(&m->lock);
75
        /*
76
         * seq_file->op->..m_start/m_stop/m_next may do special actions
77
         * or optimisations based on the file->f_version, so we want to
78
         * pass the file->f_version to those methods.
79
         *
80
         * seq_file->version is just copy of f_version, and seq_file
81
         * methods can treat it simply as file version.
82
         * It is copied in first and copied out after all operations.
83
         * It is convenient to have it as  part of structure to avoid the
84
         * need of passing another argument to all the seq_file methods.
85
         */
86
        m->version = file->f_version;
87
        /* grab buffer if we didn't have one */
88
        if (!m->buf) {
89
                m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL);
90
                if (!m->buf)
91
                        goto Enomem;
92
        }
93
        /* if not empty - flush it first */
94
        if (m->count) {
95
                n = min(m->count, size);
96
                err = copy_to_user(buf, m->buf + m->from, n);
97
                if (err)
98
                        goto Efault;
99
                m->count -= n;
100
                m->from += n;
101
                size -= n;
102
                buf += n;
103
                copied += n;
104
                if (!m->count)
105
                        m->index++;
106
                if (!size)
107
                        goto Done;
108
        }
109
        /* we need at least one record in buffer */
110
        while (1) {
111
                pos = m->index;
112
                p = m->op->start(m, &pos);
113
                err = PTR_ERR(p);
114
                if (!p || IS_ERR(p))
115
                        break;
116
                err = m->op->show(m, p);
117
                if (err)
118
                        break;
119
                if (m->count < m->size)
120
                        goto Fill;
121
                m->op->stop(m, p);
122
                kfree(m->buf);
123
                m->buf = kmalloc(m->size <<= 1, GFP_KERNEL);
124
                if (!m->buf)
125
                        goto Enomem;
126
                m->count = 0;
127
                m->version = 0;
128
        }
129
        m->op->stop(m, p);
130
        m->count = 0;
131
        goto Done;
132
Fill:
133
        /* they want more? let's try to get some more */
134
        while (m->count < size) {
135
                size_t offs = m->count;
136
                loff_t next = pos;
137
                p = m->op->next(m, p, &next);
138
                if (!p || IS_ERR(p)) {
139
                        err = PTR_ERR(p);
140
                        break;
141
                }
142
                err = m->op->show(m, p);
143
                if (err || m->count == m->size) {
144
                        m->count = offs;
145
                        break;
146
                }
147
                pos = next;
148
        }
149
        m->op->stop(m, p);
150
        n = min(m->count, size);
151
        err = copy_to_user(buf, m->buf, n);
152
        if (err)
153
                goto Efault;
154
        copied += n;
155
        m->count -= n;
156
        if (m->count)
157
                m->from = n;
158
        else
159
                pos++;
160
        m->index = pos;
161
Done:
162
        if (!copied)
163
                copied = err;
164
        else
165
                *ppos += copied;
166
        file->f_version = m->version;
167
        mutex_unlock(&m->lock);
168
        return copied;
169
Enomem:
170
        err = -ENOMEM;
171
        goto Done;
172
Efault:
173
        err = -EFAULT;
174
        goto Done;
175
}
176
EXPORT_SYMBOL(seq_read);
177
 
178
static int traverse(struct seq_file *m, loff_t offset)
179
{
180
        loff_t pos = 0, index;
181
        int error = 0;
182
        void *p;
183
 
184
        m->version = 0;
185
        index = 0;
186
        m->count = m->from = 0;
187
        if (!offset) {
188
                m->index = index;
189
                return 0;
190
        }
191
        if (!m->buf) {
192
                m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL);
193
                if (!m->buf)
194
                        return -ENOMEM;
195
        }
196
        p = m->op->start(m, &index);
197
        while (p) {
198
                error = PTR_ERR(p);
199
                if (IS_ERR(p))
200
                        break;
201
                error = m->op->show(m, p);
202
                if (error)
203
                        break;
204
                if (m->count == m->size)
205
                        goto Eoverflow;
206
                if (pos + m->count > offset) {
207
                        m->from = offset - pos;
208
                        m->count -= m->from;
209
                        m->index = index;
210
                        break;
211
                }
212
                pos += m->count;
213
                m->count = 0;
214
                if (pos == offset) {
215
                        index++;
216
                        m->index = index;
217
                        break;
218
                }
219
                p = m->op->next(m, p, &index);
220
        }
221
        m->op->stop(m, p);
222
        return error;
223
 
224
Eoverflow:
225
        m->op->stop(m, p);
226
        kfree(m->buf);
227
        m->buf = kmalloc(m->size <<= 1, GFP_KERNEL);
228
        return !m->buf ? -ENOMEM : -EAGAIN;
229
}
230
 
231
/**
232
 *      seq_lseek -     ->llseek() method for sequential files.
233
 *      @file: the file in question
234
 *      @offset: new position
235
 *      @origin: 0 for absolute, 1 for relative position
236
 *
237
 *      Ready-made ->f_op->llseek()
238
 */
239
loff_t seq_lseek(struct file *file, loff_t offset, int origin)
240
{
241
        struct seq_file *m = (struct seq_file *)file->private_data;
242
        long long retval = -EINVAL;
243
 
244
        mutex_lock(&m->lock);
245
        m->version = file->f_version;
246
        switch (origin) {
247
                case 1:
248
                        offset += file->f_pos;
249
                case 0:
250
                        if (offset < 0)
251
                                break;
252
                        retval = offset;
253
                        if (offset != file->f_pos) {
254
                                while ((retval=traverse(m, offset)) == -EAGAIN)
255
                                        ;
256
                                if (retval) {
257
                                        /* with extreme prejudice... */
258
                                        file->f_pos = 0;
259
                                        m->version = 0;
260
                                        m->index = 0;
261
                                        m->count = 0;
262
                                } else {
263
                                        retval = file->f_pos = offset;
264
                                }
265
                        }
266
        }
267
        file->f_version = m->version;
268
        mutex_unlock(&m->lock);
269
        return retval;
270
}
271
EXPORT_SYMBOL(seq_lseek);
272
 
273
/**
274
 *      seq_release -   free the structures associated with sequential file.
275
 *      @file: file in question
276
 *      @inode: file->f_path.dentry->d_inode
277
 *
278
 *      Frees the structures associated with sequential file; can be used
279
 *      as ->f_op->release() if you don't have private data to destroy.
280
 */
281
int seq_release(struct inode *inode, struct file *file)
282
{
283
        struct seq_file *m = (struct seq_file *)file->private_data;
284
        kfree(m->buf);
285
        kfree(m);
286
        return 0;
287
}
288
EXPORT_SYMBOL(seq_release);
289
 
290
/**
291
 *      seq_escape -    print string into buffer, escaping some characters
292
 *      @m:     target buffer
293
 *      @s:     string
294
 *      @esc:   set of characters that need escaping
295
 *
296
 *      Puts string into buffer, replacing each occurrence of character from
297
 *      @esc with usual octal escape.  Returns 0 in case of success, -1 - in
298
 *      case of overflow.
299
 */
300
int seq_escape(struct seq_file *m, const char *s, const char *esc)
301
{
302
        char *end = m->buf + m->size;
303
        char *p;
304
        char c;
305
 
306
        for (p = m->buf + m->count; (c = *s) != '\0' && p < end; s++) {
307
                if (!strchr(esc, c)) {
308
                        *p++ = c;
309
                        continue;
310
                }
311
                if (p + 3 < end) {
312
                        *p++ = '\\';
313
                        *p++ = '0' + ((c & 0300) >> 6);
314
                        *p++ = '0' + ((c & 070) >> 3);
315
                        *p++ = '0' + (c & 07);
316
                        continue;
317
                }
318
                m->count = m->size;
319
                return -1;
320
        }
321
        m->count = p - m->buf;
322
        return 0;
323
}
324
EXPORT_SYMBOL(seq_escape);
325
 
326
int seq_printf(struct seq_file *m, const char *f, ...)
327
{
328
        va_list args;
329
        int len;
330
 
331
        if (m->count < m->size) {
332
                va_start(args, f);
333
                len = vsnprintf(m->buf + m->count, m->size - m->count, f, args);
334
                va_end(args);
335
                if (m->count + len < m->size) {
336
                        m->count += len;
337
                        return 0;
338
                }
339
        }
340
        m->count = m->size;
341
        return -1;
342
}
343
EXPORT_SYMBOL(seq_printf);
344
 
345
int seq_path(struct seq_file *m,
346
             struct vfsmount *mnt, struct dentry *dentry,
347
             char *esc)
348
{
349
        if (m->count < m->size) {
350
                char *s = m->buf + m->count;
351
                char *p = d_path(dentry, mnt, s, m->size - m->count);
352
                if (!IS_ERR(p)) {
353
                        while (s <= p) {
354
                                char c = *p++;
355
                                if (!c) {
356
                                        p = m->buf + m->count;
357
                                        m->count = s - m->buf;
358
                                        return s - p;
359
                                } else if (!strchr(esc, c)) {
360
                                        *s++ = c;
361
                                } else if (s + 4 > p) {
362
                                        break;
363
                                } else {
364
                                        *s++ = '\\';
365
                                        *s++ = '0' + ((c & 0300) >> 6);
366
                                        *s++ = '0' + ((c & 070) >> 3);
367
                                        *s++ = '0' + (c & 07);
368
                                }
369
                        }
370
                }
371
        }
372
        m->count = m->size;
373
        return -1;
374
}
375
EXPORT_SYMBOL(seq_path);
376
 
377
static void *single_start(struct seq_file *p, loff_t *pos)
378
{
379
        return NULL + (*pos == 0);
380
}
381
 
382
static void *single_next(struct seq_file *p, void *v, loff_t *pos)
383
{
384
        ++*pos;
385
        return NULL;
386
}
387
 
388
static void single_stop(struct seq_file *p, void *v)
389
{
390
}
391
 
392
int single_open(struct file *file, int (*show)(struct seq_file *, void *),
393
                void *data)
394
{
395
        struct seq_operations *op = kmalloc(sizeof(*op), GFP_KERNEL);
396
        int res = -ENOMEM;
397
 
398
        if (op) {
399
                op->start = single_start;
400
                op->next = single_next;
401
                op->stop = single_stop;
402
                op->show = show;
403
                res = seq_open(file, op);
404
                if (!res)
405
                        ((struct seq_file *)file->private_data)->private = data;
406
                else
407
                        kfree(op);
408
        }
409
        return res;
410
}
411
EXPORT_SYMBOL(single_open);
412
 
413
int single_release(struct inode *inode, struct file *file)
414
{
415
        const struct seq_operations *op = ((struct seq_file *)file->private_data)->op;
416
        int res = seq_release(inode, file);
417
        kfree(op);
418
        return res;
419
}
420
EXPORT_SYMBOL(single_release);
421
 
422
int seq_release_private(struct inode *inode, struct file *file)
423
{
424
        struct seq_file *seq = file->private_data;
425
 
426
        kfree(seq->private);
427
        seq->private = NULL;
428
        return seq_release(inode, file);
429
}
430
EXPORT_SYMBOL(seq_release_private);
431
 
432
void *__seq_open_private(struct file *f, const struct seq_operations *ops,
433
                int psize)
434
{
435
        int rc;
436
        void *private;
437
        struct seq_file *seq;
438
 
439
        private = kzalloc(psize, GFP_KERNEL);
440
        if (private == NULL)
441
                goto out;
442
 
443
        rc = seq_open(f, ops);
444
        if (rc < 0)
445
                goto out_free;
446
 
447
        seq = f->private_data;
448
        seq->private = private;
449
        return private;
450
 
451
out_free:
452
        kfree(private);
453
out:
454
        return NULL;
455
}
456
EXPORT_SYMBOL(__seq_open_private);
457
 
458
int seq_open_private(struct file *filp, const struct seq_operations *ops,
459
                int psize)
460
{
461
        return __seq_open_private(filp, ops, psize) ? 0 : -ENOMEM;
462
}
463
EXPORT_SYMBOL(seq_open_private);
464
 
465
int seq_putc(struct seq_file *m, char c)
466
{
467
        if (m->count < m->size) {
468
                m->buf[m->count++] = c;
469
                return 0;
470
        }
471
        return -1;
472
}
473
EXPORT_SYMBOL(seq_putc);
474
 
475
int seq_puts(struct seq_file *m, const char *s)
476
{
477
        int len = strlen(s);
478
        if (m->count + len < m->size) {
479
                memcpy(m->buf + m->count, s, len);
480
                m->count += len;
481
                return 0;
482
        }
483
        m->count = m->size;
484
        return -1;
485
}
486
EXPORT_SYMBOL(seq_puts);
487
 
488
struct list_head *seq_list_start(struct list_head *head, loff_t pos)
489
{
490
        struct list_head *lh;
491
 
492
        list_for_each(lh, head)
493
                if (pos-- == 0)
494
                        return lh;
495
 
496
        return NULL;
497
}
498
 
499
EXPORT_SYMBOL(seq_list_start);
500
 
501
struct list_head *seq_list_start_head(struct list_head *head, loff_t pos)
502
{
503
        if (!pos)
504
                return head;
505
 
506
        return seq_list_start(head, pos - 1);
507
}
508
 
509
EXPORT_SYMBOL(seq_list_start_head);
510
 
511
struct list_head *seq_list_next(void *v, struct list_head *head, loff_t *ppos)
512
{
513
        struct list_head *lh;
514
 
515
        lh = ((struct list_head *)v)->next;
516
        ++*ppos;
517
        return lh == head ? NULL : lh;
518
}
519
 
520
EXPORT_SYMBOL(seq_list_next);

powered by: WebSVN 2.1.0

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