Original kernel 2.4.37.5
[tomato.git] / release / src / linux / linux / fs / read_write.c
blobb0026c4ae3150583f22cc6ae34a3565faa8ccfe8
1 /*
2 * linux/fs/read_write.c
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 * Minor pieces Copyright (C) 2002 Red Hat Inc, All Rights Reserved
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include <linux/slab.h>
23 #include <linux/stat.h>
24 #include <linux/fcntl.h>
25 #include <linux/file.h>
26 #include <linux/uio.h>
27 #include <linux/smp_lock.h>
28 #include <linux/dnotify.h>
30 #include <asm/uaccess.h>
32 struct file_operations generic_ro_fops = {
33 llseek: generic_file_llseek,
34 read: generic_file_read,
35 mmap: generic_file_mmap,
38 ssize_t generic_read_dir(struct file *filp, char *buf, size_t siz, loff_t *ppos)
40 return -EISDIR;
43 int rw_verify_area(int read_write, struct file *file, loff_t *ppos, size_t count)
45 struct inode *inode;
46 loff_t pos;
48 if (unlikely(count > file->f_maxcount))
49 goto Einval;
51 pos = *ppos;
53 if (unlikely((pos < 0) || (loff_t) (pos + count) < 0))
54 goto Einval;
56 inode = file->f_dentry->d_inode;
57 if (inode->i_flock && MANDATORY_LOCK(inode))
58 return locks_mandatory_area(read_write == READ ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE, inode, file, *ppos, count);
59 return 0;
61 Einval:
62 return -EINVAL;
65 loff_t generic_file_llseek(struct file *file, loff_t offset, int origin)
67 long long retval;
69 switch (origin) {
70 case 2:
71 offset += file->f_dentry->d_inode->i_size;
72 break;
73 case 1:
74 offset += file->f_pos;
76 retval = -EINVAL;
77 if (offset>=0 && offset<=file->f_dentry->d_inode->i_sb->s_maxbytes) {
78 if (offset != file->f_pos) {
79 file->f_pos = offset;
80 file->f_reada = 0;
81 file->f_version = ++event;
83 retval = offset;
85 return retval;
88 loff_t no_llseek(struct file *file, loff_t offset, int origin)
90 return -ESPIPE;
93 loff_t default_llseek(struct file *file, loff_t offset, int origin)
95 long long retval;
97 switch (origin) {
98 case 2:
99 offset += file->f_dentry->d_inode->i_size;
100 break;
101 case 1:
102 offset += file->f_pos;
104 retval = -EINVAL;
105 if (offset >= 0) {
106 if (offset != file->f_pos) {
107 file->f_pos = offset;
108 file->f_reada = 0;
109 file->f_version = ++event;
111 retval = offset;
113 return retval;
116 static inline loff_t llseek(struct file *file, loff_t offset, int origin)
118 loff_t (*fn)(struct file *, loff_t, int);
119 loff_t retval;
121 fn = default_llseek;
122 if (file->f_op && file->f_op->llseek)
123 fn = file->f_op->llseek;
124 lock_kernel();
125 retval = fn(file, offset, origin);
126 unlock_kernel();
127 return retval;
130 asmlinkage off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
132 off_t retval;
133 struct file * file;
135 retval = -EBADF;
136 file = fget(fd);
137 if (!file)
138 goto bad;
139 retval = -EINVAL;
140 if (origin <= 2) {
141 loff_t res = llseek(file, offset, origin);
142 retval = res;
143 if (res != (loff_t)retval)
144 retval = -EOVERFLOW; /* LFS: should only happen on 32 bit platforms */
146 fput(file);
147 bad:
148 return retval;
151 #if !defined(__alpha__)
152 asmlinkage long sys_llseek(unsigned int fd, unsigned long offset_high,
153 unsigned long offset_low, loff_t * result,
154 unsigned int origin)
156 int retval;
157 struct file * file;
158 loff_t offset;
160 retval = -EBADF;
161 file = fget(fd);
162 if (!file)
163 goto bad;
164 retval = -EINVAL;
165 if (origin > 2)
166 goto out_putf;
168 offset = llseek(file, ((loff_t) offset_high << 32) | offset_low,
169 origin);
171 retval = (int)offset;
172 if (offset >= 0) {
173 retval = -EFAULT;
174 if (!copy_to_user(result, &offset, sizeof(offset)))
175 retval = 0;
177 out_putf:
178 fput(file);
179 bad:
180 return retval;
182 #endif
184 asmlinkage ssize_t sys_read(unsigned int fd, char * buf, size_t count)
186 ssize_t ret;
187 struct file * file;
189 ret = -EBADF;
190 file = fget(fd);
191 if (file) {
192 if (file->f_mode & FMODE_READ) {
193 ret = rw_verify_area(READ, file, &file->f_pos, count);
195 if (!ret) {
196 ssize_t (*read)(struct file *, char *, size_t, loff_t *);
197 ret = -EINVAL;
198 if (file->f_op && (read = file->f_op->read) != NULL)
199 ret = read(file, buf, count, &file->f_pos);
202 if (ret > 0)
203 dnotify_parent(file->f_dentry, DN_ACCESS);
204 fput(file);
206 return ret;
209 asmlinkage ssize_t sys_write(unsigned int fd, const char * buf, size_t count)
211 ssize_t ret;
212 struct file * file;
214 ret = -EBADF;
215 file = fget(fd);
216 if (file) {
217 if (file->f_mode & FMODE_WRITE) {
218 ret = rw_verify_area(WRITE, file, &file->f_pos, count);
219 if (!ret) {
220 ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
221 ret = -EINVAL;
222 if (file->f_op && (write = file->f_op->write) != NULL)
223 ret = write(file, buf, count, &file->f_pos);
226 if (ret > 0)
227 dnotify_parent(file->f_dentry, DN_MODIFY);
228 fput(file);
230 return ret;
234 static ssize_t do_readv_writev(int type, struct file *file,
235 const struct iovec * vector,
236 unsigned long count)
238 typedef ssize_t (*io_fn_t)(struct file *, char *, size_t, loff_t *);
239 typedef ssize_t (*iov_fn_t)(struct file *, const struct iovec *, unsigned long, loff_t *);
241 size_t tot_len;
242 struct iovec iovstack[UIO_FASTIOV];
243 struct iovec *iov=iovstack;
244 ssize_t ret, i;
245 io_fn_t fn;
246 iov_fn_t fnv;
249 * First get the "struct iovec" from user memory and
250 * verify all the pointers
252 ret = 0;
253 if (!count)
254 goto out_nofree;
255 ret = -EINVAL;
256 if (count > UIO_MAXIOV)
257 goto out_nofree;
258 if (!file->f_op)
259 goto out_nofree;
260 if (count > UIO_FASTIOV) {
261 ret = -ENOMEM;
262 iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL);
263 if (!iov)
264 goto out_nofree;
266 ret = -EFAULT;
267 if (copy_from_user(iov, vector, count*sizeof(*vector)))
268 goto out;
271 * Single unix specification:
272 * We should -EINVAL if an element length is not >= 0 and fitting an ssize_t
273 * The total length is fitting an ssize_t
275 * Be careful here because iov_len is a size_t not an ssize_t
278 tot_len = 0;
279 ret = -EINVAL;
280 for (i = 0 ; i < count ; i++) {
281 ssize_t len = (ssize_t) iov[i].iov_len;
282 if (len < 0) /* size_t not fitting an ssize_t .. */
283 goto out;
284 tot_len += len;
285 /* We must do this work unsigned - signed overflow is
286 undefined and gcc 3.2 now uses that fact sometimes...
288 FIXME: put in a proper limits.h for each platform */
289 #if BITS_PER_LONG==64
290 if (tot_len > 0x7FFFFFFFFFFFFFFFUL)
291 #else
292 if (tot_len > 0x7FFFFFFFUL)
293 #endif
294 goto out;
297 /* VERIFY_WRITE actually means a read, as we write to user space */
298 ret = rw_verify_area((type == VERIFY_WRITE ? READ : WRITE),
299 file, &file->f_pos, tot_len);
300 if (ret)
301 goto out;
303 fnv = (type == VERIFY_WRITE ? file->f_op->readv : file->f_op->writev);
304 if (fnv) {
305 ret = fnv(file, iov, count, &file->f_pos);
306 goto out;
309 /* VERIFY_WRITE actually means a read, as we write to user space */
310 fn = (type == VERIFY_WRITE ? file->f_op->read :
311 (io_fn_t) file->f_op->write);
313 ret = 0;
314 vector = iov;
315 while (count > 0) {
316 void * base;
317 size_t len;
318 ssize_t nr;
320 base = vector->iov_base;
321 len = vector->iov_len;
322 vector++;
323 count--;
325 nr = fn(file, base, len, &file->f_pos);
327 if (nr < 0) {
328 if (!ret) ret = nr;
329 break;
331 ret += nr;
332 if (nr != len)
333 break;
336 out:
337 if (iov != iovstack)
338 kfree(iov);
339 out_nofree:
340 /* VERIFY_WRITE actually means a read, as we write to user space */
341 if ((ret + (type == VERIFY_WRITE)) > 0)
342 dnotify_parent(file->f_dentry,
343 (type == VERIFY_WRITE) ? DN_ACCESS : DN_MODIFY);
344 return ret;
347 asmlinkage ssize_t sys_readv(unsigned long fd, const struct iovec * vector,
348 unsigned long count)
350 struct file * file;
351 ssize_t ret;
354 ret = -EBADF;
355 file = fget(fd);
356 if (!file)
357 goto bad_file;
358 if (file->f_op && (file->f_mode & FMODE_READ) &&
359 (file->f_op->readv || file->f_op->read))
360 ret = do_readv_writev(VERIFY_WRITE, file, vector, count);
361 fput(file);
363 bad_file:
364 return ret;
367 asmlinkage ssize_t sys_writev(unsigned long fd, const struct iovec * vector,
368 unsigned long count)
370 struct file * file;
371 ssize_t ret;
374 ret = -EBADF;
375 file = fget(fd);
376 if (!file)
377 goto bad_file;
378 if (file->f_op && (file->f_mode & FMODE_WRITE) &&
379 (file->f_op->writev || file->f_op->write))
380 ret = do_readv_writev(VERIFY_READ, file, vector, count);
381 fput(file);
383 bad_file:
384 return ret;
387 /* From the Single Unix Spec: pread & pwrite act like lseek to pos + op +
388 lseek back to original location. They fail just like lseek does on
389 non-seekable files. */
391 asmlinkage ssize_t sys_pread(unsigned int fd, char * buf,
392 size_t count, loff_t pos)
394 ssize_t ret;
395 struct file * file;
396 ssize_t (*read)(struct file *, char *, size_t, loff_t *);
398 ret = -EBADF;
399 file = fget(fd);
400 if (!file)
401 goto bad_file;
402 if (!(file->f_mode & FMODE_READ))
403 goto out;
404 ret = rw_verify_area(READ, file, &pos, count);
406 if (ret)
407 goto out;
408 ret = -EINVAL;
409 if (!file->f_op || !(read = file->f_op->read))
410 goto out;
411 if (pos < 0)
412 goto out;
413 ret = read(file, buf, count, &pos);
414 if (ret > 0)
415 dnotify_parent(file->f_dentry, DN_ACCESS);
416 out:
417 fput(file);
418 bad_file:
419 return ret;
422 asmlinkage ssize_t sys_pwrite(unsigned int fd, const char * buf,
423 size_t count, loff_t pos)
425 ssize_t ret;
426 struct file * file;
427 ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
429 ret = -EBADF;
430 file = fget(fd);
431 if (!file)
432 goto bad_file;
433 if (!(file->f_mode & FMODE_WRITE))
434 goto out;
435 ret = rw_verify_area(WRITE, file, &pos, count);
437 if (ret)
438 goto out;
439 ret = -EINVAL;
440 if (!file->f_op || !(write = file->f_op->write))
441 goto out;
442 if (pos < 0)
443 goto out;
445 ret = write(file, buf, count, &pos);
446 if (ret > 0)
447 dnotify_parent(file->f_dentry, DN_MODIFY);
448 out:
449 fput(file);
450 bad_file:
451 return ret;