LCOV - code coverage report
Current view: top level - lib/util - sys_rw.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 98 119 82.4 %
Date: 2024-04-21 15:09:00 Functions: 12 13 92.3 %

          Line data    Source code
       1             : /*
       2             :  * Unix SMB/CIFS implementation.
       3             :  * Samba system utilities
       4             :  * Copyright (C) Andrew Tridgell 1992-1998
       5             :  * Copyright (C) Jeremy Allison  1998-2005
       6             :  * Copyright (C) Timur Bakeyev        2005
       7             :  * Copyright (C) Bjoern Jacke    2006-2007
       8             :  *
       9             :  * This program is free software; you can redistribute it and/or modify
      10             :  * it under the terms of the GNU General Public License as published by
      11             :  * the Free Software Foundation; either version 3 of the License, or
      12             :  * (at your option) any later version.
      13             :  *
      14             :  * This program is distributed in the hope that it will be useful,
      15             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :  * GNU General Public License for more details.
      18             :  *
      19             :  * You should have received a copy of the GNU General Public License
      20             :  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
      21             :  */
      22             : 
      23             : #include "replace.h"
      24             : #include "system/filesys.h"
      25             : #include "lib/util/sys_rw.h"
      26             : #include <assert.h>
      27             : 
      28      415312 : bool sys_valid_io_range(off_t offset, size_t length)
      29             : {
      30         295 :         uint64_t last_byte_ofs;
      31             : 
      32      415312 :         if (offset < 0) {
      33          60 :                 return false;
      34             :         }
      35             : 
      36         295 :         if (offset > INT64_MAX) {
      37             :                 return false;
      38             :         }
      39             : 
      40      415252 :         if (length > UINT32_MAX) {
      41           0 :                 return false;
      42             :         }
      43             : 
      44      415252 :         last_byte_ofs = (uint64_t)offset + (uint64_t)length;
      45      415252 :         if (last_byte_ofs > INT64_MAX) {
      46          12 :                 return false;
      47             :         }
      48             : 
      49      414945 :         return true;
      50             : }
      51             : 
      52          25 : bool sys_io_ranges_overlap(size_t c1, off_t o1,
      53             :                            size_t c2, off_t o2)
      54             : {
      55          25 :         if (c1 == 0 || c2 == 0) {
      56           0 :                 return false;
      57             :         }
      58          22 :         if (o2 < o1) {
      59             :                 /*
      60             :                  *          o1
      61             :                  *          |····c1····|
      62             :                  *  o2
      63             :                  *  |····c2···| ?
      64             :                  */
      65           2 :                 return (o2 + c2 > o1);
      66             :         } else {
      67             :                 /*
      68             :                  *  o1
      69             :                  *  |····c1···|
      70             :                  *          o2
      71             :                  *          |····c2····| ?
      72             :                  */
      73          20 :                 return (o1 + c1 > o2);
      74             :         }
      75             : }
      76             : 
      77          14 : off_t sys_block_align_truncate(off_t len, off_t align)
      78             : {
      79          14 :         assert(align > 1);
      80          14 :         assert(((align - 1) & align) == 0);
      81          14 :         return len & (~align + 1);
      82             : }
      83             : 
      84          12 : off_t sys_block_align(off_t len, off_t align)
      85             : {
      86          12 :         assert(align > 1);
      87          12 :         assert(((align - 1) & align) == 0);
      88          12 :         return (len + (align - 1)) & ~(align - 1);
      89             : }
      90             : 
      91             : /*******************************************************************
      92             : A read wrapper that will deal with EINTR/EWOULDBLOCK
      93             : ********************************************************************/
      94             : 
      95     1587787 : ssize_t sys_read(int fd, void *buf, size_t count)
      96             : {
      97       18097 :         ssize_t ret;
      98             : 
      99       18097 :         do {
     100     1587788 :                 ret = read(fd, buf, count);
     101     1587788 :         } while (ret == -1 && (errno == EINTR || errno == EAGAIN ||
     102          10 :                                errno == EWOULDBLOCK));
     103             : 
     104     1587787 :         return ret;
     105             : }
     106             : 
     107             : /**
     108             :  * read wrapper, void variant:
     109             :  * This is intended to be used as a void variant of
     110             :  * read in situations where the caller wants to ignore
     111             :  * the result. Hence not checking for EAGAIN|EWOULDBLOCK.
     112             :  */
     113           0 : void sys_read_v(int fd, void *buf, size_t count)
     114             : {
     115           0 :         ssize_t ret;
     116             : 
     117           0 :         do {
     118           0 :                 ret = read(fd, buf, count);
     119           0 :         } while (ret == -1 && errno == EINTR);
     120           0 : }
     121             : 
     122             : 
     123             : /*******************************************************************
     124             : A write wrapper that will deal with EINTR/EWOULDBLOCK.
     125             : ********************************************************************/
     126             : 
     127        3589 : ssize_t sys_write(int fd, const void *buf, size_t count)
     128             : {
     129         240 :         ssize_t ret;
     130             : 
     131         240 :         do {
     132        3589 :                 ret = write(fd, buf, count);
     133        3589 :         } while (ret == -1 && (errno == EINTR || errno == EAGAIN ||
     134           0 :                                errno == EWOULDBLOCK));
     135             : 
     136        3589 :         return ret;
     137             : }
     138             : 
     139             : /**
     140             :  * write wrapper to deal with EINTR and friends.
     141             :  * void-variant that ignores the number of bytes written.
     142             :  * This is intended to be used as a void variant of
     143             :  * write in situations where the caller wants to ignore
     144             :  * the result. Hence not checking for EAGAIN|EWOULDBLOCK.
     145             :  */
     146          26 : void sys_write_v(int fd, const void *buf, size_t count)
     147             : {
     148          10 :         ssize_t ret;
     149             : 
     150          10 :         do {
     151          26 :                 ret = write(fd, buf, count);
     152          26 :         } while (ret == -1 && errno == EINTR);
     153          26 : }
     154             : 
     155             : 
     156             : /*******************************************************************
     157             : A writev wrapper that will deal with EINTR.
     158             : ********************************************************************/
     159             : 
     160      910842 : ssize_t sys_writev(int fd, const struct iovec *iov, int iovcnt)
     161             : {
     162        8179 :         ssize_t ret;
     163             : 
     164        8179 :         do {
     165      910842 :                 ret = writev(fd, iov, iovcnt);
     166      910842 :         } while (ret == -1 && (errno == EINTR || errno == EAGAIN ||
     167          83 :                                errno == EWOULDBLOCK));
     168             : 
     169      910842 :         return ret;
     170             : }
     171             : 
     172             : /*******************************************************************
     173             : A pread wrapper that will deal with EINTR
     174             : ********************************************************************/
     175             : 
     176       18921 : ssize_t sys_pread(int fd, void *buf, size_t count, off_t off)
     177             : {
     178          63 :         ssize_t ret;
     179             : 
     180          63 :         do {
     181       18921 :                 ret = pread(fd, buf, count, off);
     182       18921 :         } while (ret == -1 && errno == EINTR);
     183       18921 :         return ret;
     184             : }
     185             : 
     186             : /*******************************************************************
     187             :  A pread wrapper that will deal with EINTR and never return a short
     188             :  read unless pread returns zero meaning EOF.
     189             : ********************************************************************/
     190             : 
     191       18033 : ssize_t sys_pread_full(int fd, void *buf, size_t count, off_t off)
     192             : {
     193       18033 :         ssize_t total_read = 0;
     194       18033 :         uint8_t *curr_buf = (uint8_t *)buf;
     195       18033 :         size_t curr_count = count;
     196       18033 :         off_t curr_off = off;
     197          56 :         bool ok;
     198             : 
     199       18033 :         ok = sys_valid_io_range(off, count);
     200       18034 :         if (!ok) {
     201           0 :                 errno = EINVAL;
     202           0 :                 return -1;
     203             :         }
     204             : 
     205       34878 :         while (curr_count != 0) {
     206       18921 :                 ssize_t ret = sys_pread(fd,
     207             :                                         curr_buf,
     208             :                                         curr_count,
     209             :                                         curr_off);
     210             : 
     211       18921 :                 if (ret == -1) {
     212           0 :                         return -1;
     213             :                 }
     214       18921 :                 if (ret == 0) {
     215             :                         /* EOF */
     216        2062 :                         break;
     217             :                 }
     218             : 
     219       16844 :                 if (ret > curr_count) {
     220           0 :                         errno = EIO;
     221           0 :                         return -1;
     222             :                 }
     223             : 
     224       16844 :                 curr_buf += ret;
     225       16844 :                 curr_count -= ret;
     226       16844 :                 curr_off += ret;
     227             : 
     228       16844 :                 total_read += ret;
     229             :         }
     230             : 
     231       17978 :         return total_read;
     232             : }
     233             : 
     234             : /*******************************************************************
     235             : A write wrapper that will deal with EINTR
     236             : ********************************************************************/
     237             : 
     238      170111 : ssize_t sys_pwrite(int fd, const void *buf, size_t count, off_t off)
     239             : {
     240          66 :         ssize_t ret;
     241             : 
     242          66 :         do {
     243      170111 :                 ret = pwrite(fd, buf, count, off);
     244      170111 :         } while (ret == -1 && errno == EINTR);
     245      170111 :         return ret;
     246             : }
     247             : 
     248             : /*******************************************************************
     249             :  A pwrite wrapper that will deal with EINTR and never allow a short
     250             :  write unless the file system returns an error.
     251             : ********************************************************************/
     252             : 
     253      170111 : ssize_t sys_pwrite_full(int fd, const void *buf, size_t count, off_t off)
     254             : {
     255      170111 :         ssize_t total_written = 0;
     256      170111 :         const uint8_t *curr_buf = (const uint8_t *)buf;
     257      170111 :         size_t curr_count = count;
     258      170111 :         off_t curr_off = off;
     259          66 :         bool ok;
     260             : 
     261      170111 :         ok = sys_valid_io_range(off, count);
     262      170111 :         if (!ok) {
     263           0 :                 errno = EINVAL;
     264           0 :                 return -1;
     265             :         }
     266             : 
     267      340222 :         while (curr_count != 0) {
     268      170111 :                 ssize_t ret = sys_pwrite(fd,
     269             :                                          curr_buf,
     270             :                                          curr_count,
     271             :                                          curr_off);
     272             : 
     273      170111 :                 if (ret == -1) {
     274           0 :                         return -1;
     275             :                 }
     276      170111 :                 if (ret == 0) {
     277             :                         /* Ensure we can never spin. */
     278           0 :                         errno = ENOSPC;
     279           0 :                         return -1;
     280             :                 }
     281             : 
     282      170111 :                 if (ret > curr_count) {
     283           0 :                         errno = EIO;
     284           0 :                         return -1;
     285             :                 }
     286             : 
     287      170111 :                 curr_buf += ret;
     288      170111 :                 curr_count -= ret;
     289      170111 :                 curr_off += ret;
     290             : 
     291      170111 :                 total_written += ret;
     292             :         }
     293             : 
     294      170045 :         return total_written;
     295             : }

Generated by: LCOV version 1.14