Import 2.3.7pre3
[davej-history.git] / fs / read_write.c
blobc7ea90a69d757396e5662e9858be22ce941bdb32
1 /*
2 * linux/fs/read_write.c
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 */
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>
14 #include <asm/uaccess.h>
16 static loff_t default_llseek(struct file *file, loff_t offset, int origin)
18 long long retval;
20 switch (origin) {
21 case 2:
22 offset += file->f_dentry->d_inode->i_size;
23 break;
24 case 1:
25 offset += file->f_pos;
27 retval = -EINVAL;
28 if (offset >= 0) {
29 if (offset != file->f_pos) {
30 file->f_pos = offset;
31 file->f_reada = 0;
32 file->f_version = ++event;
34 retval = offset;
36 return retval;
39 static inline loff_t llseek(struct file *file, loff_t offset, int origin)
41 loff_t (*fn)(struct file *, loff_t, int);
43 fn = default_llseek;
44 if (file->f_op && file->f_op->llseek)
45 fn = file->f_op->llseek;
46 return fn(file, offset, origin);
49 asmlinkage off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
51 off_t retval;
52 struct file * file;
53 struct dentry * dentry;
54 struct inode * inode;
56 lock_kernel();
57 retval = -EBADF;
58 file = fget(fd);
59 if (!file)
60 goto bad;
61 /* N.B. Shouldn't this be ENOENT?? */
62 if (!(dentry = file->f_dentry) ||
63 !(inode = dentry->d_inode))
64 goto out_putf;
65 retval = -EINVAL;
66 if (origin <= 2)
67 retval = llseek(file, offset, origin);
68 out_putf:
69 fput(file);
70 bad:
71 unlock_kernel();
72 return retval;
75 #if !defined(__alpha__)
76 asmlinkage int sys_llseek(unsigned int fd, unsigned long offset_high,
77 unsigned long offset_low, loff_t * result,
78 unsigned int origin)
80 int retval;
81 struct file * file;
82 struct dentry * dentry;
83 struct inode * inode;
84 loff_t offset;
86 lock_kernel();
87 retval = -EBADF;
88 file = fget(fd);
89 if (!file)
90 goto bad;
91 /* N.B. Shouldn't this be ENOENT?? */
92 if (!(dentry = file->f_dentry) ||
93 !(inode = dentry->d_inode))
94 goto out_putf;
95 retval = -EINVAL;
96 if (origin > 2)
97 goto out_putf;
99 offset = llseek(file, ((loff_t) offset_high << 32) | offset_low,
100 origin);
102 retval = (int)offset;
103 if (offset >= 0) {
104 retval = -EFAULT;
105 if (!copy_to_user(result, &offset, sizeof(offset)))
106 retval = 0;
108 out_putf:
109 fput(file);
110 bad:
111 unlock_kernel();
112 return retval;
114 #endif
116 asmlinkage ssize_t sys_read(unsigned int fd, char * buf, size_t count)
118 ssize_t ret;
119 struct file * file;
120 ssize_t (*read)(struct file *, char *, size_t, loff_t *);
122 lock_kernel();
124 ret = -EBADF;
125 file = fget(fd);
126 if (!file)
127 goto bad_file;
128 if (!(file->f_mode & FMODE_READ))
129 goto out;
130 ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
131 file, file->f_pos, count);
132 if (ret)
133 goto out;
134 ret = -EINVAL;
135 if (!file->f_op || !(read = file->f_op->read))
136 goto out;
137 ret = read(file, buf, count, &file->f_pos);
138 out:
139 fput(file);
140 bad_file:
141 unlock_kernel();
142 return ret;
145 asmlinkage ssize_t sys_write(unsigned int fd, const char * buf, size_t count)
147 ssize_t ret;
148 struct file * file;
149 struct inode * inode;
150 ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
152 lock_kernel();
154 ret = -EBADF;
155 file = fget(fd);
156 if (!file)
157 goto bad_file;
158 if (!(file->f_mode & FMODE_WRITE))
159 goto out;
160 inode = file->f_dentry->d_inode;
161 ret = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file,
162 file->f_pos, count);
163 if (ret)
164 goto out;
165 ret = -EINVAL;
166 if (!file->f_op || !(write = file->f_op->write))
167 goto out;
169 ret = write(file, buf, count, &file->f_pos);
170 out:
171 fput(file);
172 bad_file:
173 unlock_kernel();
174 return ret;
178 static ssize_t do_readv_writev(int type, struct file *file,
179 const struct iovec * vector,
180 unsigned long count)
182 typedef ssize_t (*io_fn_t)(struct file *, char *, size_t, loff_t *);
184 size_t tot_len;
185 struct iovec iovstack[UIO_FASTIOV];
186 struct iovec *iov=iovstack;
187 ssize_t ret, i;
188 io_fn_t fn;
189 struct inode *inode;
192 * First get the "struct iovec" from user memory and
193 * verify all the pointers
195 ret = 0;
196 if (!count)
197 goto out_nofree;
198 ret = -EINVAL;
199 if (count > UIO_MAXIOV)
200 goto out_nofree;
201 if (count > UIO_FASTIOV) {
202 ret = -ENOMEM;
203 iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL);
204 if (!iov)
205 goto out_nofree;
207 ret = -EFAULT;
208 if (copy_from_user(iov, vector, count*sizeof(*vector)))
209 goto out;
211 tot_len = 0;
212 for (i = 0 ; i < count ; i++)
213 tot_len += iov[i].iov_len;
215 inode = file->f_dentry->d_inode;
216 /* VERIFY_WRITE actually means a read, as we write to user space */
217 ret = locks_verify_area((type == VERIFY_WRITE
218 ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
219 inode, file, file->f_pos, tot_len);
220 if (ret) goto out;
223 * Then do the actual IO. Note that sockets need to be handled
224 * specially as they have atomicity guarantees and can handle
225 * iovec's natively
227 if (inode->i_sock) {
228 ret = sock_readv_writev(type,inode,file,iov,count,tot_len);
229 goto out;
232 ret = -EINVAL;
233 if (!file->f_op)
234 goto out;
236 /* VERIFY_WRITE actually means a read, as we write to user space */
237 fn = file->f_op->read;
238 if (type == VERIFY_READ)
239 fn = (io_fn_t) file->f_op->write;
241 ret = 0;
242 vector = iov;
243 while (count > 0) {
244 void * base;
245 size_t len;
246 ssize_t nr;
248 base = vector->iov_base;
249 len = vector->iov_len;
250 vector++;
251 count--;
253 nr = fn(file, base, len, &file->f_pos);
255 if (nr < 0) {
256 if (!ret) ret = nr;
257 break;
259 ret += nr;
260 if (nr != len)
261 break;
264 out:
265 if (iov != iovstack)
266 kfree(iov);
267 out_nofree:
268 return ret;
271 asmlinkage ssize_t sys_readv(unsigned long fd, const struct iovec * vector,
272 unsigned long count)
274 struct file * file;
275 ssize_t ret;
277 lock_kernel();
279 ret = -EBADF;
280 file = fget(fd);
281 if (!file)
282 goto bad_file;
283 if (file->f_op && file->f_op->read && (file->f_mode & FMODE_READ))
284 ret = do_readv_writev(VERIFY_WRITE, file, vector, count);
285 fput(file);
287 bad_file:
288 unlock_kernel();
289 return ret;
292 asmlinkage ssize_t sys_writev(unsigned long fd, const struct iovec * vector,
293 unsigned long count)
295 struct file * file;
296 ssize_t ret;
298 lock_kernel();
300 ret = -EBADF;
301 file = fget(fd);
302 if (!file)
303 goto bad_file;
304 if (file->f_op && file->f_op->write && (file->f_mode & FMODE_WRITE)) {
305 ret = do_readv_writev(VERIFY_READ, file, vector, count);
307 fput(file);
309 bad_file:
310 unlock_kernel();
311 return ret;
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. */
318 asmlinkage ssize_t sys_pread(unsigned int fd, char * buf,
319 size_t count, loff_t pos)
321 ssize_t ret;
322 struct file * file;
323 ssize_t (*read)(struct file *, char *, size_t, loff_t *);
325 lock_kernel();
327 ret = -EBADF;
328 file = fget(fd);
329 if (!file)
330 goto bad_file;
331 if (!(file->f_mode & FMODE_READ))
332 goto out;
333 ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
334 file, pos, count);
335 if (ret)
336 goto out;
337 ret = -EINVAL;
338 if (!file->f_op || !(read = file->f_op->read))
339 goto out;
340 if (pos < 0)
341 goto out;
342 ret = read(file, buf, count, &pos);
343 out:
344 fput(file);
345 bad_file:
346 unlock_kernel();
347 return ret;
350 asmlinkage ssize_t sys_pwrite(unsigned int fd, const char * buf,
351 size_t count, loff_t pos)
353 ssize_t ret;
354 struct file * file;
355 ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
357 lock_kernel();
359 ret = -EBADF;
360 file = fget(fd);
361 if (!file)
362 goto bad_file;
363 if (!(file->f_mode & FMODE_WRITE))
364 goto out;
365 ret = locks_verify_area(FLOCK_VERIFY_WRITE, file->f_dentry->d_inode,
366 file, pos, count);
367 if (ret)
368 goto out;
369 ret = -EINVAL;
370 if (!file->f_op || !(write = file->f_op->write))
371 goto out;
372 if (pos < 0)
373 goto out;
375 ret = write(file, buf, count, &pos);
376 out:
377 fput(file);
378 bad_file:
379 unlock_kernel();
380 return ret;