read_write.c (04b38d601239b4d9be641b412cf4b7456a041c67) read_write.c (b25472f9b96159cc0b9b7ed449448805973cd789)
1/*
2 * linux/fs/read_write.c
3 *
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 */
6
7#include <linux/slab.h>
8#include <linux/stat.h>
9#include <linux/fcntl.h>
10#include <linux/file.h>
11#include <linux/uio.h>
12#include <linux/fsnotify.h>
13#include <linux/security.h>
14#include <linux/export.h>
15#include <linux/syscalls.h>
16#include <linux/pagemap.h>
17#include <linux/splice.h>
18#include <linux/compat.h>
1/*
2 * linux/fs/read_write.c
3 *
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 */
6
7#include <linux/slab.h>
8#include <linux/stat.h>
9#include <linux/fcntl.h>
10#include <linux/file.h>
11#include <linux/uio.h>
12#include <linux/fsnotify.h>
13#include <linux/security.h>
14#include <linux/export.h>
15#include <linux/syscalls.h>
16#include <linux/pagemap.h>
17#include <linux/splice.h>
18#include <linux/compat.h>
19#include <linux/mount.h>
20#include "internal.h"
21
22#include <asm/uaccess.h>
23#include <asm/unistd.h>
24
25typedef ssize_t (*io_fn_t)(struct file *, char __user *, size_t, loff_t *);
26typedef ssize_t (*iter_fn_t)(struct kiocb *, struct iov_iter *);
27

--- 139 unchanged lines hidden (view full) ---

167 size, size);
168 default:
169 return -EINVAL;
170 }
171}
172EXPORT_SYMBOL(fixed_size_llseek);
173
174/**
19#include "internal.h"
20
21#include <asm/uaccess.h>
22#include <asm/unistd.h>
23
24typedef ssize_t (*io_fn_t)(struct file *, char __user *, size_t, loff_t *);
25typedef ssize_t (*iter_fn_t)(struct kiocb *, struct iov_iter *);
26

--- 139 unchanged lines hidden (view full) ---

166 size, size);
167 default:
168 return -EINVAL;
169 }
170}
171EXPORT_SYMBOL(fixed_size_llseek);
172
173/**
174 * no_seek_end_llseek - llseek implementation for fixed-sized devices
175 * @file: file structure to seek on
176 * @offset: file offset to seek to
177 * @whence: type of seek
178 *
179 */
180loff_t no_seek_end_llseek(struct file *file, loff_t offset, int whence)
181{
182 switch (whence) {
183 case SEEK_SET: case SEEK_CUR:
184 return generic_file_llseek_size(file, offset, whence,
185 ~0ULL, 0);
186 default:
187 return -EINVAL;
188 }
189}
190EXPORT_SYMBOL(no_seek_end_llseek);
191
192/**
193 * no_seek_end_llseek_size - llseek implementation for fixed-sized devices
194 * @file: file structure to seek on
195 * @offset: file offset to seek to
196 * @whence: type of seek
197 * @size: maximal offset allowed
198 *
199 */
200loff_t no_seek_end_llseek_size(struct file *file, loff_t offset, int whence, loff_t size)
201{
202 switch (whence) {
203 case SEEK_SET: case SEEK_CUR:
204 return generic_file_llseek_size(file, offset, whence,
205 size, 0);
206 default:
207 return -EINVAL;
208 }
209}
210EXPORT_SYMBOL(no_seek_end_llseek_size);
211
212/**
175 * noop_llseek - No Operation Performed llseek implementation
176 * @file: file structure to seek on
177 * @offset: file offset to seek to
178 * @whence: type of seek
179 *
180 * This is an implementation of ->llseek useable for the rare special case when
181 * userspace expects the seek to succeed but the (device) file is actually not
182 * able to perform the seek. In this case you use noop_llseek() instead of

--- 208 unchanged lines hidden (view full) ---

391 if (count >= -pos) /* both values are in 0..LLONG_MAX */
392 return -EOVERFLOW;
393 } else if (unlikely((loff_t) (pos + count) < 0)) {
394 if (!unsigned_offsets(file))
395 return retval;
396 }
397
398 if (unlikely(inode->i_flctx && mandatory_lock(inode))) {
213 * noop_llseek - No Operation Performed llseek implementation
214 * @file: file structure to seek on
215 * @offset: file offset to seek to
216 * @whence: type of seek
217 *
218 * This is an implementation of ->llseek useable for the rare special case when
219 * userspace expects the seek to succeed but the (device) file is actually not
220 * able to perform the seek. In this case you use noop_llseek() instead of

--- 208 unchanged lines hidden (view full) ---

429 if (count >= -pos) /* both values are in 0..LLONG_MAX */
430 return -EOVERFLOW;
431 } else if (unlikely((loff_t) (pos + count) < 0)) {
432 if (!unsigned_offsets(file))
433 return retval;
434 }
435
436 if (unlikely(inode->i_flctx && mandatory_lock(inode))) {
399 retval = locks_mandatory_area(inode, file, pos, pos + count - 1,
400 read_write == READ ? F_RDLCK : F_WRLCK);
437 retval = locks_mandatory_area(
438 read_write == READ ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE,
439 inode, file, pos, count);
401 if (retval < 0)
402 return retval;
403 }
404 retval = security_file_permission(file,
405 read_write == READ ? MAY_READ : MAY_WRITE);
406 if (retval)
407 return retval;
408 return count > MAX_RW_COUNT ? MAX_RW_COUNT : count;

--- 913 unchanged lines hidden (view full) ---

1322 if (unlikely(put_user(pos, offset)))
1323 return -EFAULT;
1324 return ret;
1325 }
1326
1327 return do_sendfile(out_fd, in_fd, NULL, count, 0);
1328}
1329#endif
440 if (retval < 0)
441 return retval;
442 }
443 retval = security_file_permission(file,
444 read_write == READ ? MAY_READ : MAY_WRITE);
445 if (retval)
446 return retval;
447 return count > MAX_RW_COUNT ? MAX_RW_COUNT : count;

--- 913 unchanged lines hidden (view full) ---

1361 if (unlikely(put_user(pos, offset)))
1362 return -EFAULT;
1363 return ret;
1364 }
1365
1366 return do_sendfile(out_fd, in_fd, NULL, count, 0);
1367}
1368#endif
1330
1331/*
1332 * copy_file_range() differs from regular file read and write in that it
1333 * specifically allows return partial success. When it does so is up to
1334 * the copy_file_range method.
1335 */
1336ssize_t vfs_copy_file_range(struct file *file_in, loff_t pos_in,
1337 struct file *file_out, loff_t pos_out,
1338 size_t len, unsigned int flags)
1339{
1340 struct inode *inode_in = file_inode(file_in);
1341 struct inode *inode_out = file_inode(file_out);
1342 ssize_t ret;
1343
1344 if (flags != 0)
1345 return -EINVAL;
1346
1347 /* copy_file_range allows full ssize_t len, ignoring MAX_RW_COUNT */
1348 ret = rw_verify_area(READ, file_in, &pos_in, len);
1349 if (ret >= 0)
1350 ret = rw_verify_area(WRITE, file_out, &pos_out, len);
1351 if (ret < 0)
1352 return ret;
1353
1354 if (!(file_in->f_mode & FMODE_READ) ||
1355 !(file_out->f_mode & FMODE_WRITE) ||
1356 (file_out->f_flags & O_APPEND))
1357 return -EBADF;
1358
1359 /* this could be relaxed once a method supports cross-fs copies */
1360 if (inode_in->i_sb != inode_out->i_sb)
1361 return -EXDEV;
1362
1363 if (len == 0)
1364 return 0;
1365
1366 ret = mnt_want_write_file(file_out);
1367 if (ret)
1368 return ret;
1369
1370 ret = -EOPNOTSUPP;
1371 if (file_out->f_op->copy_file_range)
1372 ret = file_out->f_op->copy_file_range(file_in, pos_in, file_out,
1373 pos_out, len, flags);
1374 if (ret == -EOPNOTSUPP)
1375 ret = do_splice_direct(file_in, &pos_in, file_out, &pos_out,
1376 len > MAX_RW_COUNT ? MAX_RW_COUNT : len, 0);
1377
1378 if (ret > 0) {
1379 fsnotify_access(file_in);
1380 add_rchar(current, ret);
1381 fsnotify_modify(file_out);
1382 add_wchar(current, ret);
1383 }
1384 inc_syscr(current);
1385 inc_syscw(current);
1386
1387 mnt_drop_write_file(file_out);
1388
1389 return ret;
1390}
1391EXPORT_SYMBOL(vfs_copy_file_range);
1392
1393SYSCALL_DEFINE6(copy_file_range, int, fd_in, loff_t __user *, off_in,
1394 int, fd_out, loff_t __user *, off_out,
1395 size_t, len, unsigned int, flags)
1396{
1397 loff_t pos_in;
1398 loff_t pos_out;
1399 struct fd f_in;
1400 struct fd f_out;
1401 ssize_t ret = -EBADF;
1402
1403 f_in = fdget(fd_in);
1404 if (!f_in.file)
1405 goto out2;
1406
1407 f_out = fdget(fd_out);
1408 if (!f_out.file)
1409 goto out1;
1410
1411 ret = -EFAULT;
1412 if (off_in) {
1413 if (copy_from_user(&pos_in, off_in, sizeof(loff_t)))
1414 goto out;
1415 } else {
1416 pos_in = f_in.file->f_pos;
1417 }
1418
1419 if (off_out) {
1420 if (copy_from_user(&pos_out, off_out, sizeof(loff_t)))
1421 goto out;
1422 } else {
1423 pos_out = f_out.file->f_pos;
1424 }
1425
1426 ret = vfs_copy_file_range(f_in.file, pos_in, f_out.file, pos_out, len,
1427 flags);
1428 if (ret > 0) {
1429 pos_in += ret;
1430 pos_out += ret;
1431
1432 if (off_in) {
1433 if (copy_to_user(off_in, &pos_in, sizeof(loff_t)))
1434 ret = -EFAULT;
1435 } else {
1436 f_in.file->f_pos = pos_in;
1437 }
1438
1439 if (off_out) {
1440 if (copy_to_user(off_out, &pos_out, sizeof(loff_t)))
1441 ret = -EFAULT;
1442 } else {
1443 f_out.file->f_pos = pos_out;
1444 }
1445 }
1446
1447out:
1448 fdput(f_out);
1449out1:
1450 fdput(f_in);
1451out2:
1452 return ret;
1453}
1454
1455static int clone_verify_area(struct file *file, loff_t pos, u64 len, bool write)
1456{
1457 struct inode *inode = file_inode(file);
1458
1459 if (unlikely(pos < 0))
1460 return -EINVAL;
1461
1462 if (unlikely((loff_t) (pos + len) < 0))
1463 return -EINVAL;
1464
1465 if (unlikely(inode->i_flctx && mandatory_lock(inode))) {
1466 loff_t end = len ? pos + len - 1 : OFFSET_MAX;
1467 int retval;
1468
1469 retval = locks_mandatory_area(inode, file, pos, end,
1470 write ? F_WRLCK : F_RDLCK);
1471 if (retval < 0)
1472 return retval;
1473 }
1474
1475 return security_file_permission(file, write ? MAY_WRITE : MAY_READ);
1476}
1477
1478int vfs_clone_file_range(struct file *file_in, loff_t pos_in,
1479 struct file *file_out, loff_t pos_out, u64 len)
1480{
1481 struct inode *inode_in = file_inode(file_in);
1482 struct inode *inode_out = file_inode(file_out);
1483 int ret;
1484
1485 if (inode_in->i_sb != inode_out->i_sb ||
1486 file_in->f_path.mnt != file_out->f_path.mnt)
1487 return -EXDEV;
1488
1489 if (S_ISDIR(inode_in->i_mode) || S_ISDIR(inode_out->i_mode))
1490 return -EISDIR;
1491 if (!S_ISREG(inode_in->i_mode) || !S_ISREG(inode_out->i_mode))
1492 return -EOPNOTSUPP;
1493
1494 if (!(file_in->f_mode & FMODE_READ) ||
1495 !(file_out->f_mode & FMODE_WRITE) ||
1496 (file_out->f_flags & O_APPEND) ||
1497 !file_in->f_op->clone_file_range)
1498 return -EBADF;
1499
1500 ret = clone_verify_area(file_in, pos_in, len, false);
1501 if (ret)
1502 return ret;
1503
1504 ret = clone_verify_area(file_out, pos_out, len, true);
1505 if (ret)
1506 return ret;
1507
1508 if (pos_in + len > i_size_read(inode_in))
1509 return -EINVAL;
1510
1511 ret = mnt_want_write_file(file_out);
1512 if (ret)
1513 return ret;
1514
1515 ret = file_in->f_op->clone_file_range(file_in, pos_in,
1516 file_out, pos_out, len);
1517 if (!ret) {
1518 fsnotify_access(file_in);
1519 fsnotify_modify(file_out);
1520 }
1521
1522 mnt_drop_write_file(file_out);
1523 return ret;
1524}
1525EXPORT_SYMBOL(vfs_clone_file_range);