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); | |