| 1783 | remaining bytes in addition to the remaining records. */ |
| 1784 | |
| 1785 | static intmax_t |
| 1786 | skip (int fdesc, char const *file, intmax_t records, idx_t blocksize, |
| 1787 | idx_t *bytes) |
| 1788 | { |
| 1789 | /* Try lseek and if an error indicates it was an inappropriate operation -- |
| 1790 | or if the file offset is not representable as an off_t -- |
| 1791 | fall back on using read. */ |
| 1792 | |
| 1793 | errno = 0; |
| 1794 | off_t offset; |
| 1795 | if (! ckd_mul (&offset, records, blocksize) |
| 1796 | && ! ckd_add (&offset, offset, *bytes) |
| 1797 | && 0 <= lseek (fdesc, offset, SEEK_CUR)) |
| 1798 | { |
| 1799 | if (fdesc == STDIN_FILENO) |
| 1800 | { |
| 1801 | struct stat st; |
| 1802 | if (ifstat (STDIN_FILENO, &st) != 0) |
| 1803 | error (EXIT_FAILURE, errno, _("cannot fstat %s"), quoteaf (file)); |
| 1804 | if (usable_st_size (&st) && 0 < st.st_size && 0 <= input_offset |
| 1805 | && st.st_size - input_offset < offset) |
| 1806 | { |
| 1807 | /* When skipping past EOF, return the number of _full_ blocks |
| 1808 | * that are not skipped, and set offset to EOF, so the caller |
| 1809 | * can determine the requested skip was not satisfied. */ |
| 1810 | records = ( offset - st.st_size ) / blocksize; |
| 1811 | offset = st.st_size - input_offset; |
| 1812 | } |
| 1813 | else |
| 1814 | records = 0; |
| 1815 | advance_input_offset (offset); |
| 1816 | } |
| 1817 | else |
| 1818 | { |
| 1819 | records = 0; |
| 1820 | *bytes = 0; |
| 1821 | } |
| 1822 | return records; |
| 1823 | } |
| 1824 | else |
| 1825 | { |
| 1826 | int lseek_errno = errno; |
| 1827 | |
| 1828 | /* The seek request may have failed above if it was too big |
| 1829 | (> device size, > max file size, etc.) |
| 1830 | Or it may not have been done at all (> OFF_T_MAX). |
| 1831 | Therefore try to seek to the end of the file, |
| 1832 | to avoid redundant reading. */ |
| 1833 | if (lseek (fdesc, 0, SEEK_END) >= 0) |
| 1834 | { |
| 1835 | /* File is seekable, and we're at the end of it, and |
| 1836 | size <= OFF_T_MAX. So there's no point using read to advance. */ |
| 1837 | |
| 1838 | if (!lseek_errno) |
| 1839 | { |
| 1840 | /* The original seek was not attempted as offset > OFF_T_MAX. |
| 1841 | We should error for write as can't get to the desired |
| 1842 | location, even if OFF_T_MAX < max file size. |
no test coverage detected