/* See LICENSE file for copyright and license details. */
#include "common.h"
void
writeall(int fd, const void *data, size_t n, const char *fname)
{
const char *text = data;
ssize_t r;
while (n) {
r = write(fd, text, n);
if (r < 0) {
if (errno == EINTR)
continue;
eprintf("write %s:", fname);
}
text = &text[r];
n -= (size_t)r;
}
}
void
filecpy(int fd, off_t src, off_t len, const char *fname)
{
char buf[8UL << 10];
ssize_t r;
size_t n;
size_t off;
while (len) {
read_again:
r = pread(fd, buf, sizeof(buf), src);
if (r <= 0) {
if (!r)
eprintf("%s: unexpected end of file", fname);
if (errno == EINTR)
goto read_again;
eprintf("pread %s:", fname);
}
src += (off_t)r;
len -= (off_t)r;
n = (size_t)r;
for (off = 0; off < n;) {
write_again:
r = write(fd, &buf[off], n - off);
if (r < 0) {
if (errno == EINTR)
goto write_again;
eprintf("write %s:", fname);
}
off += (size_t)r;
}
}
}
off_t
filesize(int fd, const char *fname)
{
struct stat st;
if (fstat(fd, &st))
eprintf("fstat %s:", fname);
switch (st.st_mode & S_IFMT) {
case S_IFREG:
break;
case S_IFBLK:
if (ioctl(fd, BLKGETSIZE64, &st.st_size) < 0)
eprintf("ioctl %s BLKGETSIZE64:", fname);
break;
default:
eprintf("%s: not a regular file or block device", fname);
}
return st.st_size;
}
#if defined(__linux__)
char *
get_device_name(unsigned int devmajor, unsigned int devminor)
{
char dev[2 * 3 * sizeof(int) + 3];
size_t devlen;
char buf[PATH_MAX];
struct dirent *f;
DIR *dir;
int dfd, fd;
ssize_t r;
size_t off;
devlen = (size_t)sprintf(dev, "%u:%u\n", devmajor, devminor);
dir = opendir("/sys/class/block");
if (!dir) {
weprintf("opendir /sys/class/block:");
return NULL;
}
dfd = dirfd(dir);
if (dfd < 0) {
weprintf("dirfd /sys/class/block:");
goto fail;
}
while ((errno = 0, f = readdir(dir))) {
if (f->d_name[0] == '.')
continue;
if (strlen(f->d_name) > sizeof(buf) - sizeof("/dev"))
continue;
stpcpy(stpcpy(buf, f->d_name), "/dev");
fd = openat(dfd, buf, O_RDONLY);
if (fd < 0)
continue;
off = 0;
while (off < sizeof(buf)) {
r = read(fd, &buf[off], sizeof(buf) - off);
if (!r)
goto complete;
if (r < 0) {
if (errno == EINTR)
continue;
goto next;
}
off += (size_t)r;
}
goto next;
complete:
if (off == devlen && !memcmp(dev, buf, devlen)) {
close(fd);
closedir(dir);
return strdup(f->d_name);
}
next:
close(fd);
}
if (errno)
weprintf("readdir /sys/class/block:");
fail:
closedir(dir);
return NULL;
}
#endif