1
2
3
4
5
6
7#include <linux/malloc.h>
8#include <linux/stat.h>
9#include <linux/fcntl.h>
10#include <linux/file.h>
11#include <linux/uio.h>
12#include <linux/smp_lock.h>
13
14#include <asm/uaccess.h>
15
16static loff_t default_llseek(struct file *file, loff_t offset, int origin)
17{
18 long long retval;
19
20 switch (origin) {
21 case 2:
22 offset += file->f_dentry->d_inode->i_size;
23 break;
24 case 1:
25 offset += file->f_pos;
26 }
27 retval = -EINVAL;
28 if (offset >= 0) {
29 if (offset != file->f_pos) {
30 file->f_pos = offset;
31 file->f_reada = 0;
32 file->f_version = ++global_event;
33 }
34 retval = offset;
35 }
36 return retval;
37}
38
39static inline loff_t llseek(struct file *file, loff_t offset, int origin)
40{
41 loff_t (*fn)(struct file *, loff_t, int);
42
43 fn = default_llseek;
44 if (file->f_op && file->f_op->llseek)
45 fn = file->f_op->llseek;
46 return fn(file, offset, origin);
47}
48
49asmlinkage off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
50{
51 off_t retval;
52 struct file * file;
53 struct dentry * dentry;
54 struct inode * inode;
55
56 lock_kernel();
57 retval = -EBADF;
58 file = fget(fd);
59 if (!file)
60 goto bad;
61
62 if (!(dentry = file->f_dentry) ||
63 !(inode = dentry->d_inode))
64 goto out_putf;
65 retval = -EINVAL;
66 if (origin <= 2)
67 retval = llseek(file, offset, origin);
68out_putf:
69 fput(file);
70bad:
71 unlock_kernel();
72 return retval;
73}
74
75#if !defined(__alpha__)
76asmlinkage int sys_llseek(unsigned int fd, unsigned long offset_high,
77 unsigned long offset_low, loff_t * result,
78 unsigned int origin)
79{
80 int retval;
81 struct file * file;
82 struct dentry * dentry;
83 struct inode * inode;
84 loff_t offset;
85
86 lock_kernel();
87 retval = -EBADF;
88 file = fget(fd);
89 if (!file)
90 goto bad;
91
92 if (!(dentry = file->f_dentry) ||
93 !(inode = dentry->d_inode))
94 goto out_putf;
95 retval = -EINVAL;
96 if (origin > 2)
97 goto out_putf;
98
99 offset = llseek(file, ((loff_t) offset_high << 32) | offset_low,
100 origin);
101
102 retval = (int)offset;
103 if (offset >= 0) {
104 retval = -EFAULT;
105 if (!copy_to_user(result, &offset, sizeof(offset)))
106 retval = 0;
107 }
108out_putf:
109 fput(file);
110bad:
111 unlock_kernel();
112 return retval;
113}
114#endif
115
116asmlinkage ssize_t sys_read(unsigned int fd, char * buf, size_t count)
117{
118 ssize_t ret;
119 struct file * file;
120 ssize_t (*read)(struct file *, char *, size_t, loff_t *);
121
122 lock_kernel();
123
124 ret = -EBADF;
125 file = fget(fd);
126 if (!file)
127 goto bad_file;
128 if (!(file->f_mode & FMODE_READ))
129 goto out;
130 ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
131 file, file->f_pos, count);
132 if (ret)
133 goto out;
134 ret = -EINVAL;
135 if (!file->f_op || !(read = file->f_op->read))
136 goto out;
137 ret = read(file, buf, count, &file->f_pos);
138out:
139 fput(file);
140bad_file:
141 unlock_kernel();
142 return ret;
143}
144
145asmlinkage ssize_t sys_write(unsigned int fd, const char * buf, size_t count)
146{
147 ssize_t ret;
148 struct file * file;
149 struct inode * inode;
150 ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
151
152 lock_kernel();
153
154 ret = -EBADF;
155 file = fget(fd);
156 if (!file)
157 goto bad_file;
158 if (!(file->f_mode & FMODE_WRITE))
159 goto out;
160 inode = file->f_dentry->d_inode;
161 ret = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file,
162 file->f_pos, count);
163 if (ret)
164 goto out;
165 ret = -EINVAL;
166 if (!file->f_op || !(write = file->f_op->write))
167 goto out;
168
169 fs_down(&inode->i_sem);
170 ret = write(file, buf, count, &file->f_pos);
171 fs_up(&inode->i_sem);
172out:
173 fput(file);
174bad_file:
175 unlock_kernel();
176 return ret;
177}
178
179
180static ssize_t do_readv_writev(int type, struct file *file,
181 const struct iovec * vector,
182 unsigned long count)
183{
184 typedef ssize_t (*io_fn_t)(struct file *, char *, size_t, loff_t *);
185
186 size_t tot_len;
187 struct iovec iovstack[UIO_FASTIOV];
188 struct iovec *iov=iovstack;
189 ssize_t ret, i;
190 io_fn_t fn;
191 struct inode *inode;
192
193
194
195
196
197 ret = 0;
198 if (!count)
199 goto out_nofree;
200 ret = -EINVAL;
201 if (count > UIO_MAXIOV)
202 goto out_nofree;
203 if (count > UIO_FASTIOV) {
204 ret = -ENOMEM;
205 iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL);
206 if (!iov)
207 goto out_nofree;
208 }
209 ret = -EFAULT;
210 if (copy_from_user(iov, vector, count*sizeof(*vector)))
211 goto out;
212
213
214
215 tot_len = 0;
216 ret = -EINVAL;
217 for (i = 0 ; i < count ; i++) {
218 size_t tmp = tot_len;
219 int len = iov[i].iov_len;
220 if (len < 0)
221 goto out;
222 (u32)tot_len += len;
223 if (tot_len < tmp || tot_len < (u32)len)
224 goto out;
225 }
226
227 inode = file->f_dentry->d_inode;
228
229 ret = locks_verify_area((type == VERIFY_WRITE
230 ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
231 inode, file, file->f_pos, tot_len);
232 if (ret) goto out;
233
234
235
236
237
238
239 if (inode->i_sock) {
240 ret = sock_readv_writev(type,inode,file,iov,count,tot_len);
241 goto out;
242 }
243
244 ret = -EINVAL;
245 if (!file->f_op)
246 goto out;
247
248
249 fn = file->f_op->read;
250 if (type == VERIFY_READ)
251 fn = (io_fn_t) file->f_op->write;
252
253 ret = 0;
254 vector = iov;
255 while (count > 0) {
256 void * base;
257 size_t len;
258 ssize_t nr;
259
260 base = vector->iov_base;
261 len = vector->iov_len;
262 vector++;
263 count--;
264
265 nr = fn(file, base, len, &file->f_pos);
266
267 if (nr < 0) {
268 if (!ret) ret = nr;
269 break;
270 }
271 ret += nr;
272 if (nr != len)
273 break;
274 }
275
276out:
277 if (iov != iovstack)
278 kfree(iov);
279out_nofree:
280 return ret;
281}
282
283asmlinkage ssize_t sys_readv(unsigned long fd, const struct iovec * vector,
284 unsigned long count)
285{
286 struct file * file;
287 ssize_t ret;
288
289 lock_kernel();
290
291 ret = -EBADF;
292 file = fget(fd);
293 if (!file)
294 goto bad_file;
295 if (file->f_op && file->f_op->read && (file->f_mode & FMODE_READ))
296 ret = do_readv_writev(VERIFY_WRITE, file, vector, count);
297 fput(file);
298
299bad_file:
300 unlock_kernel();
301 return ret;
302}
303
304asmlinkage ssize_t sys_writev(unsigned long fd, const struct iovec * vector,
305 unsigned long count)
306{
307 struct file * file;
308 ssize_t ret;
309
310 lock_kernel();
311
312 ret = -EBADF;
313 file = fget(fd);
314 if (!file)
315 goto bad_file;
316 if (file->f_op && file->f_op->write && (file->f_mode & FMODE_WRITE)) {
317 fs_down(&file->f_dentry->d_inode->i_sem);
318 ret = do_readv_writev(VERIFY_READ, file, vector, count);
319 fs_up(&file->f_dentry->d_inode->i_sem);
320 }
321 fput(file);
322
323bad_file:
324 unlock_kernel();
325 return ret;
326}
327
328
329
330
331
332asmlinkage ssize_t sys_pread(unsigned int fd, char * buf,
333 size_t count, loff_t pos)
334{
335 ssize_t ret;
336 struct file * file;
337 ssize_t (*read)(struct file *, char *, size_t, loff_t *);
338
339 lock_kernel();
340
341 ret = -EBADF;
342 file = fget(fd);
343 if (!file)
344 goto bad_file;
345 if (!(file->f_mode & FMODE_READ))
346 goto out;
347 ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
348 file, pos, count);
349 if (ret)
350 goto out;
351 ret = -EINVAL;
352 if (!file->f_op || !(read = file->f_op->read))
353 goto out;
354 if (pos < 0)
355 goto out;
356 ret = read(file, buf, count, &pos);
357out:
358 fput(file);
359bad_file:
360 unlock_kernel();
361 return ret;
362}
363
364asmlinkage ssize_t sys_pwrite(unsigned int fd, const char * buf,
365 size_t count, loff_t pos)
366{
367 ssize_t ret;
368 struct file * file;
369 ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
370
371 lock_kernel();
372
373 ret = -EBADF;
374 file = fget(fd);
375 if (!file)
376 goto bad_file;
377 if (!(file->f_mode & FMODE_WRITE))
378 goto out;
379 ret = locks_verify_area(FLOCK_VERIFY_WRITE, file->f_dentry->d_inode,
380 file, pos, count);
381 if (ret)
382 goto out;
383 ret = -EINVAL;
384 if (!file->f_op || !(write = file->f_op->write))
385 goto out;
386 if (pos < 0)
387 goto out;
388
389 fs_down(&file->f_dentry->d_inode->i_sem);
390 ret = write(file, buf, count, &pos);
391 fs_up(&file->f_dentry->d_inode->i_sem);
392
393out:
394 fput(file);
395bad_file:
396 unlock_kernel();
397 return ret;
398}
399