2014-11-19 16:33:06 +03:00
/*
* Unix SMB / CIFS implementation .
* Samba system utilities
* Copyright ( C ) Andrew Tridgell 1992 - 1998
* Copyright ( C ) Jeremy Allison 1998 - 2005
* Copyright ( C ) Timur Bakeyev 2005
* Copyright ( C ) Bjoern Jacke 2006 - 2007
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# include "replace.h"
# include "system/filesys.h"
2015-10-12 16:57:34 +03:00
# include "lib/util/sys_rw.h"
2021-06-22 19:58:21 +03:00
# include <assert.h>
2014-11-19 16:33:06 +03:00
2020-05-08 14:06:54 +03:00
bool sys_valid_io_range ( off_t offset , size_t length )
{
uint64_t last_byte_ofs ;
if ( offset < 0 ) {
return false ;
}
if ( offset > INT64_MAX ) {
return false ;
}
if ( length > UINT32_MAX ) {
return false ;
}
last_byte_ofs = ( uint64_t ) offset + ( uint64_t ) length ;
if ( last_byte_ofs > INT64_MAX ) {
return false ;
}
return true ;
}
2021-06-26 13:21:19 +03:00
bool sys_io_ranges_overlap ( size_t c1 , off_t o1 ,
size_t c2 , off_t o2 )
{
if ( c1 = = 0 | | c2 = = 0 ) {
return false ;
}
if ( o2 < o1 ) {
/*
* o1
* | · · · · c1 · · · · |
* o2
* | · · · · c2 · · · | ?
*/
return ( o2 + c2 > o1 ) ;
} else {
/*
* o1
* | · · · · c1 · · · |
* o2
* | · · · · c2 · · · · | ?
*/
return ( o1 + c1 > o2 ) ;
}
}
2021-06-22 19:58:21 +03:00
off_t sys_block_align_truncate ( off_t len , off_t align )
{
assert ( align > 1 ) ;
assert ( ( ( align - 1 ) & align ) = = 0 ) ;
return len & ( ~ align + 1 ) ;
}
off_t sys_block_align ( off_t len , off_t align )
{
assert ( align > 1 ) ;
assert ( ( ( align - 1 ) & align ) = = 0 ) ;
return ( len + ( align - 1 ) ) & ~ ( align - 1 ) ;
}
2014-11-19 16:33:06 +03:00
/*******************************************************************
A read wrapper that will deal with EINTR / EWOULDBLOCK
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
ssize_t sys_read ( int fd , void * buf , size_t count )
{
ssize_t ret ;
do {
ret = read ( fd , buf , count ) ;
} while ( ret = = - 1 & & ( errno = = EINTR | | errno = = EAGAIN | |
errno = = EWOULDBLOCK ) ) ;
return ret ;
}
2016-03-25 03:28:27 +03:00
/**
* read wrapper , void variant :
* This is intended to be used as a void variant of
* read in situations where the caller wants to ignore
* the result . Hence not checking for EAGAIN | EWOULDBLOCK .
*/
void sys_read_v ( int fd , void * buf , size_t count )
{
ssize_t ret ;
do {
ret = read ( fd , buf , count ) ;
} while ( ret = = - 1 & & errno = = EINTR ) ;
}
2014-11-19 16:33:06 +03:00
/*******************************************************************
A write wrapper that will deal with EINTR / EWOULDBLOCK .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
ssize_t sys_write ( int fd , const void * buf , size_t count )
{
ssize_t ret ;
do {
ret = write ( fd , buf , count ) ;
} while ( ret = = - 1 & & ( errno = = EINTR | | errno = = EAGAIN | |
errno = = EWOULDBLOCK ) ) ;
return ret ;
}
2016-03-25 03:28:56 +03:00
/**
* write wrapper to deal with EINTR and friends .
* void - variant that ignores the number of bytes written .
* This is intended to be used as a void variant of
* write in situations where the caller wants to ignore
* the result . Hence not checking for EAGAIN | EWOULDBLOCK .
*/
void sys_write_v ( int fd , const void * buf , size_t count )
{
ssize_t ret ;
do {
ret = write ( fd , buf , count ) ;
} while ( ret = = - 1 & & errno = = EINTR ) ;
}
2014-11-19 16:33:06 +03:00
/*******************************************************************
A writev wrapper that will deal with EINTR .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
ssize_t sys_writev ( int fd , const struct iovec * iov , int iovcnt )
{
ssize_t ret ;
do {
ret = writev ( fd , iov , iovcnt ) ;
} while ( ret = = - 1 & & ( errno = = EINTR | | errno = = EAGAIN | |
errno = = EWOULDBLOCK ) ) ;
return ret ;
}
/*******************************************************************
A pread wrapper that will deal with EINTR
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
ssize_t sys_pread ( int fd , void * buf , size_t count , off_t off )
{
ssize_t ret ;
do {
ret = pread ( fd , buf , count , off ) ;
} while ( ret = = - 1 & & errno = = EINTR ) ;
return ret ;
}
2020-05-07 22:32:48 +03:00
/*******************************************************************
A pread wrapper that will deal with EINTR and never return a short
read unless pread returns zero meaning EOF .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
ssize_t sys_pread_full ( int fd , void * buf , size_t count , off_t off )
{
ssize_t total_read = 0 ;
uint8_t * curr_buf = ( uint8_t * ) buf ;
size_t curr_count = count ;
off_t curr_off = off ;
bool ok ;
ok = sys_valid_io_range ( off , count ) ;
if ( ! ok ) {
errno = EINVAL ;
return - 1 ;
}
while ( curr_count ! = 0 ) {
ssize_t ret = sys_pread ( fd ,
curr_buf ,
curr_count ,
curr_off ) ;
if ( ret = = - 1 ) {
return - 1 ;
}
if ( ret = = 0 ) {
/* EOF */
break ;
}
if ( ret > curr_count ) {
errno = EIO ;
return - 1 ;
}
curr_buf + = ret ;
curr_count - = ret ;
curr_off + = ret ;
total_read + = ret ;
}
return total_read ;
}
2014-11-19 16:33:06 +03:00
/*******************************************************************
A write wrapper that will deal with EINTR
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
ssize_t sys_pwrite ( int fd , const void * buf , size_t count , off_t off )
{
ssize_t ret ;
do {
ret = pwrite ( fd , buf , count , off ) ;
} while ( ret = = - 1 & & errno = = EINTR ) ;
return ret ;
}
2020-05-07 22:34:32 +03:00
/*******************************************************************
A pwrite wrapper that will deal with EINTR and never allow a short
write unless the file system returns an error .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
ssize_t sys_pwrite_full ( int fd , const void * buf , size_t count , off_t off )
{
ssize_t total_written = 0 ;
const uint8_t * curr_buf = ( const uint8_t * ) buf ;
size_t curr_count = count ;
off_t curr_off = off ;
bool ok ;
ok = sys_valid_io_range ( off , count ) ;
if ( ! ok ) {
errno = EINVAL ;
return - 1 ;
}
while ( curr_count ! = 0 ) {
ssize_t ret = sys_pwrite ( fd ,
curr_buf ,
curr_count ,
curr_off ) ;
if ( ret = = - 1 ) {
return - 1 ;
}
if ( ret = = 0 ) {
/* Ensure we can never spin. */
errno = ENOSPC ;
return - 1 ;
}
if ( ret > curr_count ) {
errno = EIO ;
return - 1 ;
}
curr_buf + = ret ;
curr_count - = ret ;
curr_off + = ret ;
total_written + = ret ;
}
return total_written ;
}