mirror of
https://codeberg.org/libreboot/lbmk.git
synced 2026-07-11 05:52:36 +02:00
lbutils/file: only support real pread/pwrite
the portable version was written for fun, but it's bloat, and makes the code hard to read. every unix since about 2005 has these functions. Signed-off-by: Leah Rowe <leah@libreboot.org>
This commit is contained in:
@@ -88,17 +88,6 @@ int fchmod(int fd, mode_t mode);
|
|||||||
#define MAX_ZERO_RW_RETRY 5
|
#define MAX_ZERO_RW_RETRY 5
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef REAL_POS_IO
|
|
||||||
#define REAL_POS_IO 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef LOOP_EAGAIN
|
|
||||||
#define LOOP_EAGAIN 1
|
|
||||||
#endif
|
|
||||||
#ifndef LOOP_EINTR
|
|
||||||
#define LOOP_EINTR 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef _FILE_OFFSET_BITS
|
#ifndef _FILE_OFFSET_BITS
|
||||||
#define _FILE_OFFSET_BITS 64
|
#define _FILE_OFFSET_BITS 64
|
||||||
#endif
|
#endif
|
||||||
@@ -179,9 +168,6 @@ int fchmod(int fd, mode_t mode);
|
|||||||
#define ARGC_3 3
|
#define ARGC_3 3
|
||||||
#define ARGC_4 4
|
#define ARGC_4 4
|
||||||
|
|
||||||
#define NO_LOOP_EAGAIN 0
|
|
||||||
#define NO_LOOP_EINTR 0
|
|
||||||
|
|
||||||
/* For checking if an fd is a normal file.
|
/* For checking if an fd is a normal file.
|
||||||
* Portable for old Unix e.g. v7 (S_IFREG),
|
* Portable for old Unix e.g. v7 (S_IFREG),
|
||||||
* 4.2BSD (S_IFMT), POSIX (S_ISREG).
|
* 4.2BSD (S_IFMT), POSIX (S_ISREG).
|
||||||
@@ -477,18 +463,15 @@ ssize_t rw_gbe_file_exact(int fd, unsigned char *mem, size_t nrw,
|
|||||||
|
|
||||||
int fsync_dir(const char *path);
|
int fsync_dir(const char *path);
|
||||||
ssize_t rw_file_exact(int fd, unsigned char *mem, size_t len,
|
ssize_t rw_file_exact(int fd, unsigned char *mem, size_t len,
|
||||||
off_t off, int rw_type, int loop_eagain, int loop_eintr,
|
off_t off, int rw_type, size_t max_retries, int off_reset);
|
||||||
size_t max_retries, int off_reset);
|
|
||||||
ssize_t prw(int fd, void *mem, size_t nrw,
|
ssize_t prw(int fd, void *mem, size_t nrw,
|
||||||
off_t off, int rw_type, int loop_eagain, int loop_eintr,
|
off_t off, int rw_type);
|
||||||
int off_reset);
|
|
||||||
int io_args(int fd, void *mem, size_t nrw,
|
int io_args(int fd, void *mem, size_t nrw,
|
||||||
off_t off, int rw_type);
|
off_t off, int rw_type);
|
||||||
int check_file(int fd, struct stat *st);
|
int check_file(int fd, struct stat *st);
|
||||||
ssize_t rw_over_nrw(ssize_t r, size_t nrw);
|
ssize_t rw_over_nrw(ssize_t r, size_t nrw);
|
||||||
off_t lseek_on_eintr(int fd, off_t off,
|
off_t lseek_on_eintr(int fd, off_t off,
|
||||||
int whence, int loop_eagain, int loop_eintr);
|
int whence, int loop_eagain, int loop_eintr);
|
||||||
int try_err(int loop_err, int errval);
|
|
||||||
ssize_t read_on_eintr(int fd,
|
ssize_t read_on_eintr(int fd,
|
||||||
void *buf, size_t count);
|
void *buf, size_t count);
|
||||||
ssize_t write_on_eintr(int fd,
|
ssize_t write_on_eintr(int fd,
|
||||||
@@ -635,10 +618,6 @@ typedef char bool_skip_checksum_read[(SKIP_CHECKSUM_READ==0)?1:-1];
|
|||||||
typedef char bool_checksum_read[(CHECKSUM_READ==1)?1:-1];
|
typedef char bool_checksum_read[(CHECKSUM_READ==1)?1:-1];
|
||||||
typedef char bool_skip_checksum_write[(SKIP_CHECKSUM_WRITE==0)?1:-1];
|
typedef char bool_skip_checksum_write[(SKIP_CHECKSUM_WRITE==0)?1:-1];
|
||||||
typedef char bool_checksum_write[(CHECKSUM_WRITE==1)?1:-1];
|
typedef char bool_checksum_write[(CHECKSUM_WRITE==1)?1:-1];
|
||||||
typedef char bool_loop_eintr[(LOOP_EINTR==1||LOOP_EINTR==0)?1:-1];
|
|
||||||
typedef char bool_loop_eagain[(LOOP_EAGAIN==1||LOOP_EAGAIN==0)?1:-1];
|
|
||||||
typedef char bool_no_loop_eintr[(NO_LOOP_EINTR==0)?1:-1];
|
|
||||||
typedef char bool_no_loop_eagain[(NO_LOOP_EAGAIN==0)?1:-1];
|
|
||||||
typedef char bool_off_err[(OFF_ERR==0)?1:-1];
|
typedef char bool_off_err[(OFF_ERR==0)?1:-1];
|
||||||
typedef char bool_off_reset[(OFF_RESET==0||OFF_RESET==1)?1:-1];
|
typedef char bool_off_reset[(OFF_RESET==0||OFF_RESET==1)?1:-1];
|
||||||
|
|
||||||
|
|||||||
@@ -496,8 +496,8 @@ cat_buf(unsigned char *b)
|
|||||||
err_exit(errno, "null pointer in cat command");
|
err_exit(errno, "null pointer in cat command");
|
||||||
|
|
||||||
if (rw_file_exact(STDOUT_FILENO, b,
|
if (rw_file_exact(STDOUT_FILENO, b,
|
||||||
GBE_PART_SIZE, 0, IO_WRITE, LOOP_EAGAIN, LOOP_EINTR,
|
GBE_PART_SIZE, 0, IO_WRITE, MAX_ZERO_RW_RETRY, OFF_ERR)
|
||||||
MAX_ZERO_RW_RETRY, OFF_ERR) < 0)
|
< 0)
|
||||||
err_exit(errno, "stdout: cat");
|
err_exit(errno, "stdout: cat");
|
||||||
}
|
}
|
||||||
void
|
void
|
||||||
|
|||||||
+16
-168
@@ -160,9 +160,7 @@ err_fsync_dir:
|
|||||||
|
|
||||||
ssize_t
|
ssize_t
|
||||||
rw_file_exact(int fd, unsigned char *mem, size_t nrw,
|
rw_file_exact(int fd, unsigned char *mem, size_t nrw,
|
||||||
off_t off, int rw_type, int loop_eagain,
|
off_t off, int rw_type, size_t max_retries, int off_reset)
|
||||||
int loop_eintr, size_t max_retries,
|
|
||||||
int off_reset)
|
|
||||||
{
|
{
|
||||||
ssize_t rval;
|
ssize_t rval;
|
||||||
ssize_t rc;
|
ssize_t rc;
|
||||||
@@ -208,8 +206,7 @@ rw_file_exact(int fd, unsigned char *mem, size_t nrw,
|
|||||||
off_cur = off + (off_t)rc;
|
off_cur = off + (off_t)rc;
|
||||||
|
|
||||||
rval = prw(fd, mem_cur, nrw_cur, off_cur,
|
rval = prw(fd, mem_cur, nrw_cur, off_cur,
|
||||||
rw_type, loop_eagain, loop_eintr,
|
rw_type);
|
||||||
off_reset);
|
|
||||||
|
|
||||||
if (rval < 0)
|
if (rval < 0)
|
||||||
goto err_rw_file_exact;
|
goto err_rw_file_exact;
|
||||||
@@ -247,180 +244,42 @@ err_rw_file_exact:
|
|||||||
/* prw() - portable read-write with more
|
/* prw() - portable read-write with more
|
||||||
* safety checks than barebones libc
|
* safety checks than barebones libc
|
||||||
*
|
*
|
||||||
* If you need real pwrite/pread, just compile
|
|
||||||
* with flag: REAL_POS_IO=1
|
|
||||||
*
|
|
||||||
* A fallback is provided for regular read/write.
|
* A fallback is provided for regular read/write.
|
||||||
* rw_type can be IO_READ (read), IO_WRITE (write),
|
* rw_type can be IO_READ (read), IO_WRITE (write),
|
||||||
* IO_PREAD (pread) or IO_PWRITE
|
* IO_PREAD (pread) or IO_PWRITE
|
||||||
*
|
|
||||||
* loop_eagain does a retry loop on EAGAIN if set
|
|
||||||
* loop_eintr does a retry loop on EINTR if set
|
|
||||||
*
|
|
||||||
* race conditions on non-libc pread/pwrite:
|
|
||||||
* if a file offset changes, abort, to mitage.
|
|
||||||
*
|
|
||||||
* off_reset 1: reset the file offset *once* if
|
|
||||||
* a change was detected, assuming
|
|
||||||
* nothing else is touching it now
|
|
||||||
* off_reset 0: never reset if changed
|
|
||||||
*
|
|
||||||
* REAL_POS_IO is enabled by default in common.h
|
|
||||||
* and the fallback version was written for fun.
|
|
||||||
* You should just use the real one (REAL_POS_IO 1),
|
|
||||||
* since it is generally more reliable.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ssize_t
|
ssize_t
|
||||||
prw(int fd, void *mem, size_t nrw,
|
prw(int fd, void *mem, size_t nrw,
|
||||||
off_t off, int rw_type,
|
off_t off, int rw_type)
|
||||||
int loop_eagain, int loop_eintr,
|
|
||||||
int off_reset)
|
|
||||||
{
|
{
|
||||||
ssize_t rval;
|
ssize_t rval;
|
||||||
ssize_t r;
|
ssize_t r;
|
||||||
int positional_rw;
|
|
||||||
struct stat st;
|
struct stat st;
|
||||||
#if !defined(REAL_POS_IO) || \
|
|
||||||
REAL_POS_IO < 1
|
|
||||||
off_t verified;
|
|
||||||
off_t off_orig;
|
|
||||||
off_t off_last;
|
|
||||||
#endif
|
|
||||||
int saved_errno = errno;
|
int saved_errno = errno;
|
||||||
errno = 0;
|
errno = 0;
|
||||||
|
|
||||||
if (io_args(fd, mem, nrw, off, rw_type)
|
if (io_args(fd, mem, nrw, off, rw_type) == -1)
|
||||||
== -1)
|
return set_errno(saved_errno, EIO);
|
||||||
goto err_prw;
|
|
||||||
|
|
||||||
r = -1;
|
r = -1;
|
||||||
|
|
||||||
/* do not use loop_eagain on
|
if (rw_type == IO_WRITE)
|
||||||
* normal files
|
r = write_on_eintr(fd, mem, nrw);
|
||||||
*/
|
else if (rw_type == IO_READ)
|
||||||
|
r = read_on_eintr(fd, mem, nrw);
|
||||||
|
else if (rw_type == IO_PWRITE)
|
||||||
|
r = pwrite_on_eintr(fd, mem, nrw, off);
|
||||||
|
else if (rw_type == IO_PREAD)
|
||||||
|
r = pread_on_eintr(fd, mem, nrw, off);
|
||||||
|
|
||||||
if (!loop_eagain) {
|
if ((rval = rw_over_nrw(r, nrw)) < 0)
|
||||||
/* check whether the file
|
return set_errno(saved_errno, EIO);
|
||||||
* changed
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (check_file(fd, &st) == -1)
|
|
||||||
goto err_prw;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rw_type >= IO_PREAD)
|
|
||||||
positional_rw = 1; /* pread/pwrite */
|
|
||||||
else
|
|
||||||
positional_rw = 0; /* read/write */
|
|
||||||
|
|
||||||
try_rw_again:
|
|
||||||
|
|
||||||
if (!positional_rw) {
|
|
||||||
#if defined(REAL_POS_IO) && \
|
|
||||||
REAL_POS_IO > 0
|
|
||||||
real_pread_pwrite:
|
|
||||||
#endif
|
|
||||||
if (rw_type == IO_WRITE)
|
|
||||||
r = write_on_eintr(fd, mem, nrw);
|
|
||||||
else if (rw_type == IO_READ)
|
|
||||||
r = read_on_eintr(fd, mem, nrw);
|
|
||||||
#if defined(REAL_POS_IO) && \
|
|
||||||
REAL_POS_IO > 0
|
|
||||||
else if (rw_type == IO_PWRITE)
|
|
||||||
r = pwrite_on_eintr(fd, mem, nrw, off);
|
|
||||||
else if (rw_type == IO_PREAD)
|
|
||||||
r = pread_on_eintr(fd, mem, nrw, off);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (r == -1 && (errno == try_err(loop_eintr, EINTR)
|
|
||||||
|| errno == try_err(loop_eagain, EAGAIN)))
|
|
||||||
goto try_rw_again;
|
|
||||||
|
|
||||||
rval = rw_over_nrw(r, nrw);
|
|
||||||
if (rval < 0)
|
|
||||||
goto err_prw;
|
|
||||||
|
|
||||||
|
if (rval >= 0 && !errno)
|
||||||
errno = saved_errno;
|
errno = saved_errno;
|
||||||
|
|
||||||
return rval;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(REAL_POS_IO) && \
|
|
||||||
REAL_POS_IO > 0
|
|
||||||
goto real_pread_pwrite;
|
|
||||||
#else
|
|
||||||
if ((off_orig = lseek_on_eintr(fd, (off_t)0, SEEK_CUR,
|
|
||||||
loop_eagain, loop_eintr)) == (off_t)-1) {
|
|
||||||
r = -1;
|
|
||||||
} else if (lseek_on_eintr(fd, off, SEEK_SET,
|
|
||||||
loop_eagain, loop_eintr) == (off_t)-1) {
|
|
||||||
r = -1;
|
|
||||||
} else {
|
|
||||||
verified = lseek_on_eintr(fd, (off_t)0, SEEK_CUR,
|
|
||||||
loop_eagain, loop_eintr);
|
|
||||||
|
|
||||||
/* abort if the offset changed,
|
|
||||||
* indicating race condition. if
|
|
||||||
* off_reset enabled, reset *ONCE*
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (off_reset && off != verified)
|
|
||||||
lseek_on_eintr(fd, off, SEEK_SET,
|
|
||||||
loop_eagain, loop_eintr);
|
|
||||||
|
|
||||||
do {
|
|
||||||
/* check offset again, repeatedly.
|
|
||||||
* even if off_reset is set, this
|
|
||||||
* aborts if offsets change again
|
|
||||||
*/
|
|
||||||
|
|
||||||
verified = lseek_on_eintr(fd, (off_t)0, SEEK_CUR,
|
|
||||||
loop_eagain, loop_eintr);
|
|
||||||
|
|
||||||
if (off != verified) {
|
|
||||||
|
|
||||||
errno = EBUSY;
|
|
||||||
goto err_prw;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rw_type == IO_PREAD)
|
|
||||||
r = read_on_eintr(fd, mem, nrw);
|
|
||||||
else if (rw_type == IO_PWRITE)
|
|
||||||
r = write_on_eintr(fd, mem, nrw);
|
|
||||||
|
|
||||||
if (rw_over_nrw(r, nrw) == -1)
|
|
||||||
break;
|
|
||||||
|
|
||||||
} while (r == -1 &&
|
|
||||||
(errno == try_err(loop_eintr, EINTR) ||
|
|
||||||
errno == try_err(loop_eagain, EAGAIN)));
|
|
||||||
}
|
|
||||||
|
|
||||||
saved_errno = errno;
|
|
||||||
|
|
||||||
off_last = lseek_on_eintr(fd, off_orig, SEEK_SET,
|
|
||||||
loop_eagain, loop_eintr);
|
|
||||||
|
|
||||||
if (off_last != off_orig) {
|
|
||||||
errno = saved_errno;
|
|
||||||
goto err_prw;
|
|
||||||
}
|
|
||||||
|
|
||||||
errno = saved_errno;
|
|
||||||
|
|
||||||
rval = rw_over_nrw(r, nrw);
|
|
||||||
if (rval < 0)
|
|
||||||
goto err_prw;
|
|
||||||
|
|
||||||
errno = saved_errno;
|
|
||||||
|
|
||||||
return rval;
|
return rval;
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
err_prw:
|
|
||||||
return set_errno(saved_errno, EIO);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -501,17 +360,6 @@ if_err_sys(int condition)
|
|||||||
return 0;
|
return 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
/* errno can never be -1, so you can
|
|
||||||
* use this to conditionally set an integer
|
|
||||||
* for comparison. see example in lseek_on_eintr
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
try_err(int loop_err, int errval)
|
|
||||||
{
|
|
||||||
if (loop_err)
|
|
||||||
return errval;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
fs_rename_at(int olddirfd, const char *old,
|
fs_rename_at(int olddirfd, const char *old,
|
||||||
|
|||||||
@@ -104,8 +104,7 @@ read_file(void)
|
|||||||
/* read main file
|
/* read main file
|
||||||
*/
|
*/
|
||||||
_r = rw_file_exact(f->gbe_fd, f->buf, f->gbe_file_size,
|
_r = rw_file_exact(f->gbe_fd, f->buf, f->gbe_file_size,
|
||||||
0, IO_PREAD, NO_LOOP_EAGAIN, LOOP_EINTR,
|
0, IO_PREAD, MAX_ZERO_RW_RETRY, OFF_ERR);
|
||||||
MAX_ZERO_RW_RETRY, OFF_ERR);
|
|
||||||
|
|
||||||
if (_r < 0)
|
if (_r < 0)
|
||||||
err_exit(errno, "%s: read failed", f->fname);
|
err_exit(errno, "%s: read failed", f->fname);
|
||||||
@@ -113,8 +112,7 @@ read_file(void)
|
|||||||
/* copy to tmpfile
|
/* copy to tmpfile
|
||||||
*/
|
*/
|
||||||
_r = rw_file_exact(f->tmp_fd, f->buf, f->gbe_file_size,
|
_r = rw_file_exact(f->tmp_fd, f->buf, f->gbe_file_size,
|
||||||
0, IO_PWRITE, NO_LOOP_EAGAIN, LOOP_EINTR,
|
0, IO_PWRITE, MAX_ZERO_RW_RETRY, OFF_ERR);
|
||||||
MAX_ZERO_RW_RETRY, OFF_ERR);
|
|
||||||
|
|
||||||
if (_r < 0)
|
if (_r < 0)
|
||||||
err_exit(errno, "%s: %s: copy failed",
|
err_exit(errno, "%s: %s: copy failed",
|
||||||
@@ -137,8 +135,7 @@ read_file(void)
|
|||||||
err_exit(errno, "%s: fsync (tmpfile copy)", f->tname);
|
err_exit(errno, "%s: fsync (tmpfile copy)", f->tname);
|
||||||
|
|
||||||
_r = rw_file_exact(f->tmp_fd, f->bufcmp, f->gbe_file_size,
|
_r = rw_file_exact(f->tmp_fd, f->bufcmp, f->gbe_file_size,
|
||||||
0, IO_PREAD, NO_LOOP_EAGAIN, LOOP_EINTR,
|
0, IO_PREAD, MAX_ZERO_RW_RETRY, OFF_ERR);
|
||||||
MAX_ZERO_RW_RETRY, OFF_ERR);
|
|
||||||
|
|
||||||
if (_r < 0)
|
if (_r < 0)
|
||||||
err_exit(errno, "%s: read failed (cmp)", f->tname);
|
err_exit(errno, "%s: read failed (cmp)", f->tname);
|
||||||
@@ -570,8 +567,7 @@ rw_gbe_file_exact(int fd, unsigned char *mem, size_t nrw,
|
|||||||
goto err_rw_gbe_file_exact;
|
goto err_rw_gbe_file_exact;
|
||||||
|
|
||||||
r = rw_file_exact(fd, mem, nrw, off, rw_type,
|
r = rw_file_exact(fd, mem, nrw, off, rw_type,
|
||||||
NO_LOOP_EAGAIN, LOOP_EINTR, MAX_ZERO_RW_RETRY,
|
MAX_ZERO_RW_RETRY, OFF_ERR);
|
||||||
OFF_ERR);
|
|
||||||
|
|
||||||
return rw_over_nrw(r, nrw);
|
return rw_over_nrw(r, nrw);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user