~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/fs/read_write.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  *  linux/fs/read_write.c
  3  *
  4  *  Copyright (C) 1991, 1992  Linus Torvalds
  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 #include <linux/dnotify.h>
 14 
 15 #include <asm/uaccess.h>
 16 
 17 struct file_operations generic_ro_fops = {
 18         read:           generic_file_read,
 19         mmap:           generic_file_mmap,
 20 };
 21 
 22 ssize_t generic_read_dir(struct file *filp, char *buf, size_t siz, loff_t *ppos)
 23 {
 24         return -EISDIR;
 25 }
 26 
 27 loff_t default_llseek(struct file *file, loff_t offset, int origin)
 28 {
 29         long long retval;
 30 
 31         switch (origin) {
 32                 case 2:
 33                         offset += file->f_dentry->d_inode->i_size;
 34                         break;
 35                 case 1:
 36                         offset += file->f_pos;
 37         }
 38         retval = -EINVAL;
 39         if (offset >= 0) {
 40                 if (offset != file->f_pos) {
 41                         file->f_pos = offset;
 42                         file->f_reada = 0;
 43                         file->f_version = ++event;
 44                 }
 45                 retval = offset;
 46         }
 47         return retval;
 48 }
 49 
 50 static inline loff_t llseek(struct file *file, loff_t offset, int origin)
 51 {
 52         loff_t (*fn)(struct file *, loff_t, int);
 53         loff_t retval;
 54 
 55         fn = default_llseek;
 56         if (file->f_op && file->f_op->llseek)
 57                 fn = file->f_op->llseek;
 58         lock_kernel();
 59         retval = fn(file, offset, origin);
 60         unlock_kernel();
 61         return retval;
 62 }
 63 
 64 asmlinkage off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
 65 {
 66         off_t retval;
 67         struct file * file;
 68 
 69         retval = -EBADF;
 70         file = fget(fd);
 71         if (!file)
 72                 goto bad;
 73         retval = -EINVAL;
 74         if (origin <= 2) {
 75                 loff_t res = llseek(file, offset, origin);
 76                 retval = res;
 77                 if (res != (loff_t)retval)
 78                         retval = -EOVERFLOW;    /* LFS: should only happen on 32 bit platforms */
 79         }
 80         fput(file);
 81 bad:
 82         return retval;
 83 }
 84 
 85 #if !defined(__alpha__)
 86 asmlinkage long sys_llseek(unsigned int fd, unsigned long offset_high,
 87                            unsigned long offset_low, loff_t * result,
 88                            unsigned int origin)
 89 {
 90         int retval;
 91         struct file * file;
 92         loff_t offset;
 93 
 94         retval = -EBADF;
 95         file = fget(fd);
 96         if (!file)
 97                 goto bad;
 98         retval = -EINVAL;
 99         if (origin > 2)
100                 goto out_putf;
101 
102         offset = llseek(file, ((loff_t) offset_high << 32) | offset_low,
103                         origin);
104 
105         retval = (int)offset;
106         if (offset >= 0) {
107                 retval = -EFAULT;
108                 if (!copy_to_user(result, &offset, sizeof(offset)))
109                         retval = 0;
110         }
111 out_putf:
112         fput(file);
113 bad:
114         return retval;
115 }
116 #endif
117 
118 asmlinkage ssize_t sys_read(unsigned int fd, char * buf, size_t count)
119 {
120         ssize_t ret;
121         struct file * file;
122 
123         ret = -EBADF;
124         file = fget(fd);
125         if (file) {
126                 if (file->f_mode & FMODE_READ) {
127                         ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
128                                                 file, file->f_pos, count);
129                         if (!ret) {
130                                 ssize_t (*read)(struct file *, char *, size_t, loff_t *);
131                                 ret = -EINVAL;
132                                 if (file->f_op && (read = file->f_op->read) != NULL)
133                                         ret = read(file, buf, count, &file->f_pos);
134                         }
135                 }
136                 if (ret > 0)
137                         inode_dir_notify(file->f_dentry->d_parent->d_inode,
138                                 DN_ACCESS);
139                 fput(file);
140         }
141         return ret;
142 }
143 
144 asmlinkage ssize_t sys_write(unsigned int fd, const char * buf, size_t count)
145 {
146         ssize_t ret;
147         struct file * file;
148 
149         ret = -EBADF;
150         file = fget(fd);
151         if (file) {
152                 if (file->f_mode & FMODE_WRITE) {
153                         struct inode *inode = file->f_dentry->d_inode;
154                         ret = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file,
155                                 file->f_pos, count);
156                         if (!ret) {
157                                 ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
158                                 ret = -EINVAL;
159                                 if (file->f_op && (write = file->f_op->write) != NULL)
160                                         ret = write(file, buf, count, &file->f_pos);
161                         }
162                 }
163                 if (ret > 0)
164                         inode_dir_notify(file->f_dentry->d_parent->d_inode,
165                                 DN_MODIFY);
166                 fput(file);
167         }
168         return ret;
169 }
170 
171 
172 static ssize_t do_readv_writev(int type, struct file *file,
173                                const struct iovec * vector,
174                                unsigned long count)
175 {
176         typedef ssize_t (*io_fn_t)(struct file *, char *, size_t, loff_t *);
177         typedef ssize_t (*iov_fn_t)(struct file *, const struct iovec *, unsigned long, loff_t *);
178 
179         size_t tot_len;
180         struct iovec iovstack[UIO_FASTIOV];
181         struct iovec *iov=iovstack;
182         ssize_t ret, i;
183         io_fn_t fn;
184         iov_fn_t fnv;
185         struct inode *inode;
186 
187         /*
188          * First get the "struct iovec" from user memory and
189          * verify all the pointers
190          */
191         ret = 0;
192         if (!count)
193                 goto out_nofree;
194         ret = -EINVAL;
195         if (count > UIO_MAXIOV)
196                 goto out_nofree;
197         if (!file->f_op)
198                 goto out_nofree;
199         if (count > UIO_FASTIOV) {
200                 ret = -ENOMEM;
201                 iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL);
202                 if (!iov)
203                         goto out_nofree;
204         }
205         ret = -EFAULT;
206         if (copy_from_user(iov, vector, count*sizeof(*vector)))
207                 goto out;
208 
209         /* BSD readv/writev returns EINVAL if one of the iov_len
210            values < 0 or tot_len overflowed a 32-bit integer. -ink */
211         tot_len = 0;
212         ret = -EINVAL;
213         for (i = 0 ; i < count ; i++) {
214                 size_t tmp = tot_len;
215                 int len = iov[i].iov_len;
216                 if (len < 0)
217                         goto out;
218                 (u32)tot_len += len;
219                 if (tot_len < tmp || tot_len < (u32)len)
220                         goto out;
221         }
222 
223         inode = file->f_dentry->d_inode;
224         /* VERIFY_WRITE actually means a read, as we write to user space */
225         ret = locks_verify_area((type == VERIFY_WRITE
226                                  ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
227                                 inode, file, file->f_pos, tot_len);
228         if (ret) goto out;
229 
230         fnv = (type == VERIFY_WRITE ? file->f_op->readv : file->f_op->writev);
231         if (fnv) {
232                 ret = fnv(file, iov, count, &file->f_pos);
233                 goto out;
234         }
235 
236         /* VERIFY_WRITE actually means a read, as we write to user space */
237         fn = (type == VERIFY_WRITE ? file->f_op->read :
238               (io_fn_t) file->f_op->write);
239 
240         ret = 0;
241         vector = iov;
242         while (count > 0) {
243                 void * base;
244                 size_t len;
245                 ssize_t nr;
246 
247                 base = vector->iov_base;
248                 len = vector->iov_len;
249                 vector++;
250                 count--;
251 
252                 nr = fn(file, base, len, &file->f_pos);
253 
254                 if (nr < 0) {
255                         if (!ret) ret = nr;
256                         break;
257                 }
258                 ret += nr;
259                 if (nr != len)
260                         break;
261         }
262 
263 out:
264         if (iov != iovstack)
265                 kfree(iov);
266 out_nofree:
267         /* VERIFY_WRITE actually means a read, as we write to user space */
268         if ((ret + (type == VERIFY_WRITE)) > 0)
269                 inode_dir_notify(file->f_dentry->d_parent->d_inode,
270                         (type == VERIFY_WRITE) ? DN_MODIFY : DN_ACCESS);
271         return ret;
272 }
273 
274 asmlinkage ssize_t sys_readv(unsigned long fd, const struct iovec * vector,
275                              unsigned long count)
276 {
277         struct file * file;
278         ssize_t ret;
279 
280 
281         ret = -EBADF;
282         file = fget(fd);
283         if (!file)
284                 goto bad_file;
285         if (file->f_op && (file->f_mode & FMODE_READ) &&
286             (file->f_op->readv || file->f_op->read))
287                 ret = do_readv_writev(VERIFY_WRITE, file, vector, count);
288         fput(file);
289 
290 bad_file:
291         return ret;
292 }
293 
294 asmlinkage ssize_t sys_writev(unsigned long fd, const struct iovec * vector,
295                               unsigned long count)
296 {
297         struct file * file;
298         ssize_t ret;
299 
300 
301         ret = -EBADF;
302         file = fget(fd);
303         if (!file)
304                 goto bad_file;
305         if (file->f_op && (file->f_mode & FMODE_WRITE) &&
306             (file->f_op->writev || file->f_op->write))
307                 ret = do_readv_writev(VERIFY_READ, file, vector, count);
308         fput(file);
309 
310 bad_file:
311         return ret;
312 }
313 
314 /* From the Single Unix Spec: pread & pwrite act like lseek to pos + op +
315    lseek back to original location.  They fail just like lseek does on
316    non-seekable files.  */
317 
318 asmlinkage ssize_t sys_pread(unsigned int fd, char * buf,
319                              size_t count, loff_t pos)
320 {
321         ssize_t ret;
322         struct file * file;
323         ssize_t (*read)(struct file *, char *, size_t, loff_t *);
324 
325         ret = -EBADF;
326         file = fget(fd);
327         if (!file)
328                 goto bad_file;
329         if (!(file->f_mode & FMODE_READ))
330                 goto out;
331         ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
332                                 file, pos, count);
333         if (ret)
334                 goto out;
335         ret = -EINVAL;
336         if (!file->f_op || !(read = file->f_op->read))
337                 goto out;
338         if (pos < 0)
339                 goto out;
340         ret = read(file, buf, count, &pos);
341         if (ret > 0)
342                 inode_dir_notify(file->f_dentry->d_parent->d_inode, DN_ACCESS);
343 out:
344         fput(file);
345 bad_file:
346         return ret;
347 }
348 
349 asmlinkage ssize_t sys_pwrite(unsigned int fd, const char * buf,
350                               size_t count, loff_t pos)
351 {
352         ssize_t ret;
353         struct file * file;
354         ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
355 
356         ret = -EBADF;
357         file = fget(fd);
358         if (!file)
359                 goto bad_file;
360         if (!(file->f_mode & FMODE_WRITE))
361                 goto out;
362         ret = locks_verify_area(FLOCK_VERIFY_WRITE, file->f_dentry->d_inode,
363                                 file, pos, count);
364         if (ret)
365                 goto out;
366         ret = -EINVAL;
367         if (!file->f_op || !(write = file->f_op->write))
368                 goto out;
369         if (pos < 0)
370                 goto out;
371 
372         ret = write(file, buf, count, &pos);
373         if (ret > 0)
374                 inode_dir_notify(file->f_dentry->d_parent->d_inode, DN_MODIFY);
375 out:
376         fput(file);
377 bad_file:
378         return ret;
379 }
380 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.