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
32struct file_operations generic_ro_fops = {
33	llseek:		generic_file_llseek,
34	read:		generic_file_read,
35	mmap:		generic_file_mmap,
36};
37
38ssize_t generic_read_dir(struct file *filp, char *buf, size_t siz, loff_t *ppos)
39{
40	return -EISDIR;
41}
42
43loff_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
66loff_t no_llseek(struct file *file, loff_t offset, int origin)
67{
68	return -ESPIPE;
69}
70
71loff_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
94static 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
108asmlinkage 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);
125bad:
126	return retval;
127}
128
129#if !defined(__alpha__)
130asmlinkage 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	}
155out_putf:
156	fput(file);
157bad:
158	return retval;
159}
160#endif
161
162asmlinkage 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
187asmlinkage 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
214static 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	ssize_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 tmp = tot_len;
263		ssize_t len = (ssize_t) iov[i].iov_len;
264		if (len < 0)	/* size_t not fitting an ssize_t .. */
265			goto out;
266		tot_len += len;
267		if (tot_len < tmp) /* maths overflow on the ssize_t */
268			goto out;
269	}
270
271	inode = file->f_dentry->d_inode;
272	/* VERIFY_WRITE actually means a read, as we write to user space */
273	ret = locks_verify_area((type == VERIFY_WRITE
274				 ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
275				inode, file, file->f_pos, tot_len);
276	if (ret) goto out;
277
278	fnv = (type == VERIFY_WRITE ? file->f_op->readv : file->f_op->writev);
279	if (fnv) {
280		ret = fnv(file, iov, count, &file->f_pos);
281		goto out;
282	}
283
284	/* VERIFY_WRITE actually means a read, as we write to user space */
285	fn = (type == VERIFY_WRITE ? file->f_op->read :
286	      (io_fn_t) file->f_op->write);
287
288	ret = 0;
289	vector = iov;
290	while (count > 0) {
291		void * base;
292		size_t len;
293		ssize_t nr;
294
295		base = vector->iov_base;
296		len = vector->iov_len;
297		vector++;
298		count--;
299
300		nr = fn(file, base, len, &file->f_pos);
301
302		if (nr < 0) {
303			if (!ret) ret = nr;
304			break;
305		}
306		ret += nr;
307		if (nr != len)
308			break;
309	}
310
311out:
312	if (iov != iovstack)
313		kfree(iov);
314out_nofree:
315	/* VERIFY_WRITE actually means a read, as we write to user space */
316	if ((ret + (type == VERIFY_WRITE)) > 0)
317		dnotify_parent(file->f_dentry,
318			(type == VERIFY_WRITE) ? DN_MODIFY : DN_ACCESS);
319	return ret;
320}
321
322asmlinkage ssize_t sys_readv(unsigned long fd, const struct iovec * vector,
323			     unsigned long count)
324{
325	struct file * file;
326	ssize_t ret;
327
328
329	ret = -EBADF;
330	file = fget(fd);
331	if (!file)
332		goto bad_file;
333	if (file->f_op && (file->f_mode & FMODE_READ) &&
334	    (file->f_op->readv || file->f_op->read))
335		ret = do_readv_writev(VERIFY_WRITE, file, vector, count);
336	fput(file);
337
338bad_file:
339	return ret;
340}
341
342asmlinkage ssize_t sys_writev(unsigned long fd, const struct iovec * vector,
343			      unsigned long count)
344{
345	struct file * file;
346	ssize_t ret;
347
348
349	ret = -EBADF;
350	file = fget(fd);
351	if (!file)
352		goto bad_file;
353	if (file->f_op && (file->f_mode & FMODE_WRITE) &&
354	    (file->f_op->writev || file->f_op->write))
355		ret = do_readv_writev(VERIFY_READ, file, vector, count);
356	fput(file);
357
358bad_file:
359	return ret;
360}
361
362/* From the Single Unix Spec: pread & pwrite act like lseek to pos + op +
363   lseek back to original location.  They fail just like lseek does on
364   non-seekable files.  */
365
366asmlinkage ssize_t sys_pread(unsigned int fd, char * buf,
367			     size_t count, loff_t pos)
368{
369	ssize_t ret;
370	struct file * file;
371	ssize_t (*read)(struct file *, char *, size_t, loff_t *);
372
373	ret = -EBADF;
374	file = fget(fd);
375	if (!file)
376		goto bad_file;
377	if (!(file->f_mode & FMODE_READ))
378		goto out;
379	ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
380				file, pos, count);
381	if (ret)
382		goto out;
383	ret = -EINVAL;
384	if (!file->f_op || !(read = file->f_op->read))
385		goto out;
386	if (pos < 0)
387		goto out;
388	ret = read(file, buf, count, &pos);
389	if (ret > 0)
390		dnotify_parent(file->f_dentry, DN_ACCESS);
391out:
392	fput(file);
393bad_file:
394	return ret;
395}
396
397asmlinkage ssize_t sys_pwrite(unsigned int fd, const char * buf,
398			      size_t count, loff_t pos)
399{
400	ssize_t ret;
401	struct file * file;
402	ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
403
404	ret = -EBADF;
405	file = fget(fd);
406	if (!file)
407		goto bad_file;
408	if (!(file->f_mode & FMODE_WRITE))
409		goto out;
410	ret = locks_verify_area(FLOCK_VERIFY_WRITE, file->f_dentry->d_inode,
411				file, pos, count);
412	if (ret)
413		goto out;
414	ret = -EINVAL;
415	if (!file->f_op || !(write = file->f_op->write))
416		goto out;
417	if (pos < 0)
418		goto out;
419
420	ret = write(file, buf, count, &pos);
421	if (ret > 0)
422		dnotify_parent(file->f_dentry, DN_MODIFY);
423out:
424	fput(file);
425bad_file:
426	return ret;
427}
428