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
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.