more changes on original files
[linux-2.4.git] / fs / read_write.c
1 /*
2  *  linux/fs/read_write.c
3  *
4  *  Copyright (C) 1991, 1992  Linus Torvalds
5  *  Minor pieces Copyright (C) 2002 Red Hat Inc, All Rights Reserved
6  *
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.
11  *
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.
16  *
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
20  */
21
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>
29
30 #include <asm/uaccess.h>
31
32 struct file_operations generic_ro_fops = {
33         llseek:         generic_file_llseek,
34         read:           generic_file_read,
35         mmap:           generic_file_mmap,
36 };
37
38 ssize_t generic_read_dir(struct file *filp, char *buf, size_t siz, loff_t *ppos)
39 {
40         return -EISDIR;
41 }
42
43 int rw_verify_area(int read_write, struct file *file, loff_t *ppos, size_t count)
44 {
45         struct inode *inode;
46         loff_t pos;
47
48         if (unlikely(count > file->f_maxcount))
49                 goto Einval;
50
51         pos = *ppos;
52
53         if (unlikely((pos < 0) || (loff_t) (pos + count) < 0))
54                 goto Einval;
55
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;
60
61 Einval:
62         return -EINVAL;
63 }
64
65 loff_t generic_file_llseek(struct file *file, loff_t offset, int origin)
66 {
67         long long retval;
68
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;
75         }
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;
82                 }
83                 retval = offset;
84         }
85         return retval;
86 }
87
88 loff_t no_llseek(struct file *file, loff_t offset, int origin)
89 {
90         return -ESPIPE;
91 }
92
93 loff_t default_llseek(struct file *file, loff_t offset, int origin)
94 {
95         long long retval;
96
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;
103         }
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;
110                 }
111                 retval = offset;
112         }
113         return retval;
114 }
115
116 static inline loff_t llseek(struct file *file, loff_t offset, int origin)
117 {
118         loff_t (*fn)(struct file *, loff_t, int);
119         loff_t retval;
120
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;
128 }
129
130 asmlinkage off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
131 {
132         off_t retval;
133         struct file * file;
134
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 */
145         }
146         fput(file);
147 bad:
148         return retval;
149 }
150
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)
155 {
156         int retval;
157         struct file * file;
158         loff_t offset;
159
160         retval = -EBADF;
161         file = fget(fd);
162         if (!file)
163                 goto bad;
164         retval = -EINVAL;
165         if (origin > 2)
166                 goto out_putf;
167
168         offset = llseek(file, ((loff_t) offset_high << 32) | offset_low,
169                         origin);
170
171         retval = (int)offset;
172         if (offset >= 0) {
173                 retval = -EFAULT;
174                 if (!copy_to_user(result, &offset, sizeof(offset)))
175                         retval = 0;
176         }
177 out_putf:
178         fput(file);
179 bad:
180         return retval;
181 }
182 #endif
183
184 asmlinkage ssize_t sys_read(unsigned int fd, char * buf, size_t count)
185 {
186         ssize_t ret;
187         struct file * file;
188
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);
194
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);
200                         }
201                 }
202                 if (ret > 0)
203                         dnotify_parent(file->f_dentry, DN_ACCESS);
204                 fput(file);
205         }
206         return ret;
207 }
208
209 asmlinkage ssize_t sys_write(unsigned int fd, const char * buf, size_t count)
210 {
211         ssize_t ret;
212         struct file * file;
213
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);
224                         }
225                 }
226                 if (ret > 0)
227                         dnotify_parent(file->f_dentry, DN_MODIFY);
228                 fput(file);
229         }
230         return ret;
231 }
232
233
234 static ssize_t do_readv_writev(int type, struct file *file,
235                                const struct iovec * vector,
236                                unsigned long count)
237 {
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 *);
240
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;
247
248         /*
249          * First get the "struct iovec" from user memory and
250          * verify all the pointers
251          */
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;
265         }
266         ret = -EFAULT;
267         if (copy_from_user(iov, vector, count*sizeof(*vector)))
268                 goto out;
269
270         /*
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
274          *
275          * Be careful here because iov_len is a size_t not an ssize_t
276          */
277          
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... 
287                    
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;
295         }
296
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;
302
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;
307         }
308
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);
312
313         ret = 0;
314         vector = iov;
315         while (count > 0) {
316                 void * base;
317                 size_t len;
318                 ssize_t nr;
319
320                 base = vector->iov_base;
321                 len = vector->iov_len;
322                 vector++;
323                 count--;
324
325                 nr = fn(file, base, len, &file->f_pos);
326
327                 if (nr < 0) {
328                         if (!ret) ret = nr;
329                         break;
330                 }
331                 ret += nr;
332                 if (nr != len)
333                         break;
334         }
335
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;
345 }
346
347 asmlinkage ssize_t sys_readv(unsigned long fd, const struct iovec * vector,
348                              unsigned long count)
349 {
350         struct file * file;
351         ssize_t ret;
352
353
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);
362
363 bad_file:
364         return ret;
365 }
366
367 asmlinkage ssize_t sys_writev(unsigned long fd, const struct iovec * vector,
368                               unsigned long count)
369 {
370         struct file * file;
371         ssize_t ret;
372
373
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);
382
383 bad_file:
384         return ret;
385 }
386
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.  */
390
391 asmlinkage ssize_t sys_pread(unsigned int fd, char * buf,
392                              size_t count, loff_t pos)
393 {
394         ssize_t ret;
395         struct file * file;
396         ssize_t (*read)(struct file *, char *, size_t, loff_t *);
397
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);
405
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;
420 }
421
422 asmlinkage ssize_t sys_pwrite(unsigned int fd, const char * buf,
423                               size_t count, loff_t pos)
424 {
425         ssize_t ret;
426         struct file * file;
427         ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
428
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);
436
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;
444
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;
452 }