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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [fs/] [read_write.c] - Blame information for rev 1777

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

Line No. Rev Author Line
1 1627 jcastillo
/*
2
 *  linux/fs/read_write.c
3
 *
4
 *  Copyright (C) 1991, 1992  Linus Torvalds
5
 */
6
 
7
#include <linux/types.h>
8
#include <linux/errno.h>
9
#include <linux/stat.h>
10
#include <linux/kernel.h>
11
#include <linux/sched.h>
12
#include <linux/fcntl.h>
13
#include <linux/file.h>
14
#include <linux/mm.h>
15
#include <linux/uio.h>
16
 
17
#include <asm/segment.h>
18
 
19
asmlinkage long sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
20
{
21
        struct file * file;
22
        long tmp = -1;
23
 
24
        if (fd >= NR_OPEN || !(file=current->files->fd[fd]) || !(file->f_inode))
25
                return -EBADF;
26
        if (origin > 2)
27
                return -EINVAL;
28
        if (file->f_op && file->f_op->lseek)
29
                return file->f_op->lseek(file->f_inode,file,offset,origin);
30
 
31
/* this is the default handler if no lseek handler is present */
32
        switch (origin) {
33
                case 0:
34
                        tmp = offset;
35
                        break;
36
                case 1:
37
                        tmp = file->f_pos + offset;
38
                        break;
39
                case 2:
40
                        if (!file->f_inode)
41
                                return -EINVAL;
42
                        tmp = file->f_inode->i_size + offset;
43
                        break;
44
        }
45
        if (tmp < 0)
46
                return -EINVAL;
47
        if (tmp != file->f_pos) {
48
                file->f_pos = tmp;
49
                file->f_reada = 0;
50
                file->f_version = ++event;
51
        }
52
        return file->f_pos;
53
}
54
 
55
asmlinkage int sys_llseek(unsigned int fd, unsigned long offset_high,
56
                          unsigned long offset_low, loff_t * result,
57
                          unsigned int origin)
58
{
59
        struct file * file;
60
        loff_t tmp = -1;
61
        loff_t offset;
62
        int err;
63
 
64
        if (fd >= NR_OPEN || !(file=current->files->fd[fd]) || !(file->f_inode))
65
                return -EBADF;
66
        if (origin > 2)
67
                return -EINVAL;
68
        if ((err = verify_area(VERIFY_WRITE, result, sizeof(loff_t))))
69
                return err;
70
        offset = (loff_t) (((unsigned long long) offset_high << 32) | offset_low);
71
 
72
        /* if there is a fs-specific handler, we can't just ignore it.. */
73
        /* accept llseek() only for the signed long subset of long long */
74
        if (file->f_op && file->f_op->lseek) {
75
                if (offset != (long) offset)
76
                        return -EINVAL;
77
                return file->f_op->lseek(file->f_inode,file,offset,origin);
78
        }
79
 
80
        switch (origin) {
81
                case 0:
82
                        tmp = offset;
83
                        break;
84
                case 1:
85
                        tmp = file->f_pos + offset;
86
                        break;
87
                case 2:
88
                        if (!file->f_inode)
89
                                return -EINVAL;
90
                        tmp = file->f_inode->i_size + offset;
91
                        break;
92
        }
93
        if (tmp < 0)
94
                return -EINVAL;
95
        if (tmp != file->f_pos) {
96
                file->f_pos = tmp;
97
                file->f_reada = 0;
98
                file->f_version = ++event;
99
        }
100
        memcpy_tofs(result, &file->f_pos, sizeof(loff_t));
101
        return 0;
102
}
103
 
104
asmlinkage int sys_read(unsigned int fd,char * buf,int count)
105
{
106
        int error;
107
        struct file * file;
108
        struct inode * inode;
109
 
110
        error = -EBADF;
111
        file = fget(fd);
112
        if (!file)
113
                goto bad_file;
114
        inode = file->f_inode;
115
        if (!inode)
116
                goto out;
117
        error = -EBADF;
118
        if (!(file->f_mode & 1))
119
                goto out;
120
        error = -EINVAL;
121
        if (!file->f_op || !file->f_op->read)
122
                goto out;
123
        error = 0;
124
        if (count <= 0)
125
                goto out;
126
        error = locks_verify_area(FLOCK_VERIFY_READ,inode,file,file->f_pos,count);
127
        if (error)
128
                goto out;
129
        error = verify_area(VERIFY_WRITE,buf,count);
130
        if (error)
131
                goto out;
132
        error = file->f_op->read(inode,file,buf,count);
133
out:
134
        fput(file, inode);
135
bad_file:
136
        return error;
137
}
138
 
139
asmlinkage int sys_write(unsigned int fd,char * buf,unsigned int count)
140
{
141
        int error;
142
        struct file * file;
143
        struct inode * inode;
144
 
145
        error = -EBADF;
146
        file = fget(fd);
147
        if (!file)
148
                goto bad_file;
149
        inode = file->f_inode;
150
        if (!inode)
151
                goto out;
152
        if (!(file->f_mode & 2))
153
                goto out;
154
        error = -EINVAL;
155
        if (!file->f_op || !file->f_op->write)
156
                goto out;
157
        error = 0;
158
        /*
159
         *      If this was a development kernel we'd just drop the test
160
         *      its not so we do this for stricter compatibility both to
161
         *      applications and drivers.
162
         */
163
        if (!count && !IS_ZERO_WR(inode))
164
                goto out;
165
        error = locks_verify_area(FLOCK_VERIFY_WRITE,inode,file,file->f_pos,count);
166
        if (error)
167
                goto out;
168
        error = verify_area(VERIFY_READ,buf,count);
169
        if (error)
170
                goto out;
171
        /*
172
         * If data has been written to the file, remove the setuid and
173
         * the setgid bits. We do it anyway otherwise there is an
174
         * extremely exploitable race - does your OS get it right |->
175
         *
176
         * Set ATTR_FORCE so it will always be changed.
177
         */
178
        if (!suser() && (inode->i_mode & (S_ISUID | S_ISGID))) {
179
                struct iattr newattrs;
180
                /*
181
                 * Don't turn off setgid if no group execute. This special
182
                 * case marks candidates for mandatory locking.
183
                 */
184
                newattrs.ia_mode = inode->i_mode &
185
                        ~(S_ISUID | ((inode->i_mode & S_IXGRP) ? S_ISGID : 0));
186
                newattrs.ia_valid = ATTR_CTIME | ATTR_MODE | ATTR_FORCE;
187
                notify_change(inode, &newattrs);
188
        }
189
 
190
        down(&inode->i_sem);
191
        error = file->f_op->write(inode,file,buf,count);
192
        up(&inode->i_sem);
193
out:
194
        fput(file, inode);
195
bad_file:
196
        return error;
197
}
198
 
199
static int sock_readv_writev(int type, struct inode * inode, struct file * file,
200
        const struct iovec * iov, long count, long size)
201
{
202
        struct msghdr msg;
203
        struct socket *sock;
204
 
205
        sock = &inode->u.socket_i;
206
        if (!sock->ops)
207
                return -EOPNOTSUPP;
208
        msg.msg_name = NULL;
209
        msg.msg_namelen = 0;
210
        msg.msg_control = NULL;
211
        msg.msg_iov = (struct iovec *) iov;
212
        msg.msg_iovlen = count;
213
 
214
        /* read() does a VERIFY_WRITE */
215
        if (type == VERIFY_WRITE) {
216
                if (!sock->ops->recvmsg)
217
                        return -EOPNOTSUPP;
218
                return sock->ops->recvmsg(sock, &msg, size,
219
                        (file->f_flags & O_NONBLOCK), 0, NULL);
220
        }
221
        if (!sock->ops->sendmsg)
222
                return -EOPNOTSUPP;
223
        return sock->ops->sendmsg(sock, &msg, size,
224
                (file->f_flags & O_NONBLOCK), 0);
225
}
226
 
227
typedef int (*IO_fn_t)(struct inode *, struct file *, char *, int);
228
 
229
static int do_readv_writev(int type, struct inode * inode, struct file * file,
230
        const struct iovec * vector, unsigned long count)
231
{
232
        size_t tot_len;
233
        struct iovec iov[UIO_MAXIOV];
234
        int retval, i;
235
        IO_fn_t fn;
236
 
237
        /*
238
         * First get the "struct iovec" from user memory and
239
         * verify all the pointers
240
         */
241
        if (!count)
242
                return 0;
243
        if (count > UIO_MAXIOV)
244
                return -EINVAL;
245
        retval = verify_area(VERIFY_READ, vector, count*sizeof(*vector));
246
        if (retval)
247
                return retval;
248
        memcpy_fromfs(iov, vector, count*sizeof(*vector));
249
        tot_len = 0;
250
        for (i = 0 ; i < count ; i++) {
251
                tot_len += iov[i].iov_len;
252
                retval = verify_area(type, iov[i].iov_base, iov[i].iov_len);
253
                if (retval)
254
                        return retval;
255
        }
256
 
257
        retval = locks_verify_area(type == VERIFY_WRITE ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE,
258
                                   inode, file, file->f_pos, tot_len);
259
        if (retval)
260
                return retval;
261
 
262
        /*
263
         * Then do the actual IO.  Note that sockets need to be handled
264
         * specially as they have atomicity guarantees and can handle
265
         * iovec's natively
266
         */
267
        if (inode->i_sock)
268
                return sock_readv_writev(type, inode, file, iov, count, tot_len);
269
 
270
        if (!file->f_op)
271
                return -EINVAL;
272
        /* VERIFY_WRITE actually means a read, as we write to user space */
273
        fn = file->f_op->read;
274
        if (type == VERIFY_READ)
275
                fn = (IO_fn_t) file->f_op->write;
276
 
277
        if(fn==NULL)
278
                return -EOPNOTSUPP;
279
 
280
        vector = iov;
281
        while (count > 0) {
282
                void * base;
283
                int len, nr;
284
 
285
                base = vector->iov_base;
286
                len = vector->iov_len;
287
                vector++;
288
                count--;
289
                nr = fn(inode, file, base, len);
290
                if (nr < 0) {
291
                        if (retval)
292
                                break;
293
                        retval = nr;
294
                        break;
295
                }
296
                retval += nr;
297
                if (nr != len)
298
                        break;
299
        }
300
        return retval;
301
}
302
 
303
asmlinkage int sys_readv(unsigned long fd, const struct iovec * vector, long count)
304
{
305
        struct file * file;
306
        struct inode * inode;
307
 
308
        if (fd >= NR_OPEN || !(file = current->files->fd[fd]) || !(inode = file->f_inode))
309
                return -EBADF;
310
        if (!(file->f_mode & 1))
311
                return -EBADF;
312
        return do_readv_writev(VERIFY_WRITE, inode, file, vector, count);
313
}
314
 
315
asmlinkage int sys_writev(unsigned long fd, const struct iovec * vector, long count)
316
{
317
        int error;
318
        struct file * file;
319
        struct inode * inode;
320
 
321
        if (fd >= NR_OPEN || !(file = current->files->fd[fd]) || !(inode = file->f_inode))
322
                return -EBADF;
323
        if (!(file->f_mode & 2))
324
                return -EBADF;
325
        down(&inode->i_sem);
326
        error = do_readv_writev(VERIFY_READ, inode, file, vector, count);
327
        up(&inode->i_sem);
328
        return error;
329
}

powered by: WebSVN 2.1.0

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