FreeBSD/Linux Kernel Cross Reference
sys/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 loff_t generic_file_llseek(struct file *file, loff_t offset, int origin)
44 {
45 long long retval;
46
47 switch (origin) {
48 case 2:
49 offset += file->f_dentry->d_inode->i_size;
50 break;
51 case 1:
52 offset += file->f_pos;
53 }
54 retval = -EINVAL;
55 if (offset>=0 && offset<=file->f_dentry->d_inode->i_sb->s_maxbytes) {
56 if (offset != file->f_pos) {
57 file->f_pos = offset;
58 file->f_reada = 0;
59 file->f_version = ++event;
60 }
61 retval = offset;
62 }
63 return retval;
64 }
65
66 loff_t no_llseek(struct file *file, loff_t offset, int origin)
67 {
68 return -ESPIPE;
69 }
70
71 loff_t default_llseek(struct file *file, loff_t offset, int origin)
72 {
73 long long retval;
74
75 switch (origin) {
76 case 2:
77 offset += file->f_dentry->d_inode->i_size;
78 break;
79 case 1:
80 offset += file->f_pos;
81 }
82 retval = -EINVAL;
83 if (offset >= 0) {
84 if (offset != file->f_pos) {
85 file->f_pos = offset;
86 file->f_reada = 0;
87 file->f_version = ++event;
88 }
89 retval = offset;
90 }
91 return retval;
92 }
93
94 static inline loff_t llseek(struct file *file, loff_t offset, int origin)
95 {
96 loff_t (*fn)(struct file *, loff_t, int);
97 loff_t retval;
98
99 fn = default_llseek;
100 if (file->f_op && file->f_op->llseek)
101 fn = file->f_op->llseek;
102 lock_kernel();
103 retval = fn(file, offset, origin);
104 unlock_kernel();
105 return retval;
106 }
107
108 asmlinkage off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
109 {
110 off_t retval;
111 struct file * file;
112
113 retval = -EBADF;
114 file = fget(fd);
115 if (!file)
116 goto bad;
117 retval = -EINVAL;
118 if (origin <= 2) {
119 loff_t res = llseek(file, offset, origin);
120 retval = res;
121 if (res != (loff_t)retval)
122 retval = -EOVERFLOW; /* LFS: should only happen on 32 bit platforms */
123 }
124 fput(file);
125 bad:
126 return retval;
127 }
128
129 #if !defined(__alpha__)
130 asmlinkage long sys_llseek(unsigned int fd, unsigned long offset_high,
131 unsigned long offset_low, loff_t * result,
132 unsigned int origin)
133 {
134 int retval;
135 struct file * file;
136 loff_t offset;
137
138 retval = -EBADF;
139 file = fget(fd);
140 if (!file)
141 goto bad;
142 retval = -EINVAL;
143 if (origin > 2)
144 goto out_putf;
145
146 offset = llseek(file, ((loff_t) offset_high << 32) | offset_low,
147 origin);
148
149 retval = (int)offset;
150 if (offset >= 0) {
151 retval = -EFAULT;
152 if (!copy_to_user(result, &offset, sizeof(offset)))
153 retval = 0;
154 }
155 out_putf:
156 fput(file);
157 bad:
158 return retval;
159 }
160 #endif
161
162 asmlinkage ssize_t sys_read(unsigned int fd, char * buf, size_t count)
163 {
164 ssize_t ret;
165 struct file * file;
166
167 ret = -EBADF;
168 file = fget(fd);
169 if (file) {
170 if (file->f_mode & FMODE_READ) {
171 ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
172 file, file->f_pos, count);
173 if (!ret) {
174 ssize_t (*read)(struct file *, char *, size_t, loff_t *);
175 ret = -EINVAL;
176 if (file->f_op && (read = file->f_op->read) != NULL)
177 ret = read(file, buf, count, &file->f_pos);
178 }
179 }
180 if (ret > 0)
181 dnotify_parent(file->f_dentry, DN_ACCESS);
182 fput(file);
183 }
184 return ret;
185 }
186
187 asmlinkage ssize_t sys_write(unsigned int fd, const char * buf, size_t count)
188 {
189 ssize_t ret;
190 struct file * file;
191
192 ret = -EBADF;
193 file = fget(fd);
194 if (file) {
195 if (file->f_mode & FMODE_WRITE) {
196 struct inode *inode = file->f_dentry->d_inode;
197 ret = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file,
198 file->f_pos, count);
199 if (!ret) {
200 ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
201 ret = -EINVAL;
202 if (file->f_op && (write = file->f_op->write) != NULL)
203 ret = write(file, buf, count, &file->f_pos);
204 }
205 }
206 if (ret > 0)
207 dnotify_parent(file->f_dentry, DN_MODIFY);
208 fput(file);
209 }
210 return ret;
211 }
212
213
214 static ssize_t do_readv_writev(int type, struct file *file,
215 const struct iovec * vector,
216 unsigned long count)
217 {
218 typedef ssize_t (*io_fn_t)(struct file *, char *, size_t, loff_t *);
219 typedef ssize_t (*iov_fn_t)(struct file *, const struct iovec *, unsigned long, loff_t *);
220
221 size_t tot_len;
222 struct iovec iovstack[UIO_FASTIOV];
223 struct iovec *iov=iovstack;
224 ssize_t ret, i;
225 io_fn_t fn;
226 iov_fn_t fnv;
227 struct inode *inode;
228
229 /*
230 * First get the "struct iovec" from user memory and
231 * verify all the pointers
232 */
233 ret = 0;
234 if (!count)
235 goto out_nofree;
236 ret = -EINVAL;
237 if (count > UIO_MAXIOV)
238 goto out_nofree;
239 if (!file->f_op)
240 goto out_nofree;
241 if (count > UIO_FASTIOV) {
242 ret = -ENOMEM;
243 iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL);
244 if (!iov)
245 goto out_nofree;
246 }
247 ret = -EFAULT;
248 if (copy_from_user(iov, vector, count*sizeof(*vector)))
249 goto out;
250
251 /*
252 * Single unix specification:
253 * We should -EINVAL if an element length is not >= 0 and fitting an ssize_t
254 * The total length is fitting an ssize_t
255 *
256 * Be careful here because iov_len is a size_t not an ssize_t
257 */
258
259 tot_len = 0;
260 ret = -EINVAL;
261 for (i = 0 ; i < count ; i++) {
262 ssize_t len = (ssize_t) iov[i].iov_len;
263 if (len < 0) /* size_t not fitting an ssize_t .. */
264 goto out;
265 tot_len += len;
266 /* We must do this work unsigned - signed overflow is
267 undefined and gcc 3.2 now uses that fact sometimes...
268
269 FIXME: put in a proper limits.h for each platform */
270 #if BITS_PER_LONG==64
271 if (tot_len > 0x7FFFFFFFFFFFFFFFUL)
272 #else
273 if (tot_len > 0x7FFFFFFFUL)
274 #endif
275 goto out;
276 }
277
278 inode = file->f_dentry->d_inode;
279 /* VERIFY_WRITE actually means a read, as we write to user space */
280 ret = locks_verify_area((type == VERIFY_WRITE
281 ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
282 inode, file, file->f_pos, tot_len);
283 if (ret) goto out;
284
285 fnv = (type == VERIFY_WRITE ? file->f_op->readv : file->f_op->writev);
286 if (fnv) {
287 ret = fnv(file, iov, count, &file->f_pos);
288 goto out;
289 }
290
291 /* VERIFY_WRITE actually means a read, as we write to user space */
292 fn = (type == VERIFY_WRITE ? file->f_op->read :
293 (io_fn_t) file->f_op->write);
294
295 ret = 0;
296 vector = iov;
297 while (count > 0) {
298 void * base;
299 size_t len;
300 ssize_t nr;
301
302 base = vector->iov_base;
303 len = vector->iov_len;
304 vector++;
305 count--;
306
307 nr = fn(file, base, len, &file->f_pos);
308
309 if (nr < 0) {
310 if (!ret) ret = nr;
311 break;
312 }
313 ret += nr;
314 if (nr != len)
315 break;
316 }
317
318 out:
319 if (iov != iovstack)
320 kfree(iov);
321 out_nofree:
322 /* VERIFY_WRITE actually means a read, as we write to user space */
323 if ((ret + (type == VERIFY_WRITE)) > 0)
324 dnotify_parent(file->f_dentry,
325 (type == VERIFY_WRITE) ? DN_ACCESS : DN_MODIFY);
326 return ret;
327 }
328
329 asmlinkage ssize_t sys_readv(unsigned long fd, const struct iovec * vector,
330 unsigned long count)
331 {
332 struct file * file;
333 ssize_t ret;
334
335
336 ret = -EBADF;
337 file = fget(fd);
338 if (!file)
339 goto bad_file;
340 if (file->f_op && (file->f_mode & FMODE_READ) &&
341 (file->f_op->readv || file->f_op->read))
342 ret = do_readv_writev(VERIFY_WRITE, file, vector, count);
343 fput(file);
344
345 bad_file:
346 return ret;
347 }
348
349 asmlinkage ssize_t sys_writev(unsigned long fd, const struct iovec * vector,
350 unsigned long count)
351 {
352 struct file * file;
353 ssize_t ret;
354
355
356 ret = -EBADF;
357 file = fget(fd);
358 if (!file)
359 goto bad_file;
360 if (file->f_op && (file->f_mode & FMODE_WRITE) &&
361 (file->f_op->writev || file->f_op->write))
362 ret = do_readv_writev(VERIFY_READ, file, vector, count);
363 fput(file);
364
365 bad_file:
366 return ret;
367 }
368
369 /* From the Single Unix Spec: pread & pwrite act like lseek to pos + op +
370 lseek back to original location. They fail just like lseek does on
371 non-seekable files. */
372
373 asmlinkage ssize_t sys_pread(unsigned int fd, char * buf,
374 size_t count, loff_t pos)
375 {
376 ssize_t ret;
377 struct file * file;
378 ssize_t (*read)(struct file *, char *, size_t, loff_t *);
379
380 ret = -EBADF;
381 file = fget(fd);
382 if (!file)
383 goto bad_file;
384 if (!(file->f_mode & FMODE_READ))
385 goto out;
386 ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
387 file, pos, count);
388 if (ret)
389 goto out;
390 ret = -EINVAL;
391 if (!file->f_op || !(read = file->f_op->read))
392 goto out;
393 if (pos < 0)
394 goto out;
395 ret = read(file, buf, count, &pos);
396 if (ret > 0)
397 dnotify_parent(file->f_dentry, DN_ACCESS);
398 out:
399 fput(file);
400 bad_file:
401 return ret;
402 }
403
404 asmlinkage ssize_t sys_pwrite(unsigned int fd, const char * buf,
405 size_t count, loff_t pos)
406 {
407 ssize_t ret;
408 struct file * file;
409 ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
410
411 ret = -EBADF;
412 file = fget(fd);
413 if (!file)
414 goto bad_file;
415 if (!(file->f_mode & FMODE_WRITE))
416 goto out;
417 ret = locks_verify_area(FLOCK_VERIFY_WRITE, file->f_dentry->d_inode,
418 file, pos, count);
419 if (ret)
420 goto out;
421 ret = -EINVAL;
422 if (!file->f_op || !(write = file->f_op->write))
423 goto out;
424 if (pos < 0)
425 goto out;
426
427 ret = write(file, buf, count, &pos);
428 if (ret > 0)
429 dnotify_parent(file->f_dentry, DN_MODIFY);
430 out:
431 fput(file);
432 bad_file:
433 return ret;
434 }
Cache object: e6e138c3dcd6749fc2c8a33858c40a30
|