forked from florolf/casync-nano
-
Notifications
You must be signed in to change notification settings - Fork 0
/
utils.c
161 lines (125 loc) · 2.69 KB
/
utils.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#ifdef __APPLE__
#include <sys/disk.h>
#endif
#ifdef __linux__
#include <linux/fs.h>
#endif
#include "utils.h"
static int blockdevice_size(int fd, off_t *size_ptr)
#if defined(__APPLE__)
{
uint32_t size;
uint64_t count;
if (ioctl(fd, DKIOCGETBLOCKSIZE, &size) < 0) {
u_log_errno("getting device block size failed");
return -1;
}
if (ioctl(fd, DKIOCGETBLOCKCOUNT, &count) < 0) {
u_log_errno("getting device block count failed");
return -1;
}
*size_ptr = (off_t)(size * count);
return 0;
}
#elif defined(__linux__)
{
uint64_t tmp;
if (ioctl(fd, BLKGETSIZE64, &tmp) < 0) {
u_log_errno("getting block device size failed");
return -1;
}
*size_ptr = (off_t)tmp;
return 0;
}
#else
#error "blockdevice_size not implemented for target"
#endif
must_check int readall(int fd, uint8_t *buf, size_t len)
{
size_t read_bytes = 0;
while (read_bytes < len) {
ssize_t ret;
ret = read(fd, &buf[read_bytes], len - read_bytes);
if (ret < 0) {
if (errno == EINTR)
continue;
u_log_errno("read failed");
return -1;
} else if (ret == 0) {
u_log(ERR, "short read, expected %zu, got %zu", len, read_bytes);
return -1;
}
read_bytes += ret;
}
return 0;
}
must_check int preadall(int fd, uint8_t *buf, size_t len, off_t offset)
{
size_t read_bytes = 0;
while (read_bytes < len) {
ssize_t ret;
ret = pread(fd, &buf[read_bytes], len - read_bytes, offset);
if (ret < 0) {
if (errno == EINTR)
continue;
u_log_errno("read failed");
return -1;
} else if (ret == 0) {
u_log(ERR, "short read, expected %zu, got %zu", len, read_bytes);
return -1;
}
read_bytes += ret;
offset += ret;
}
return 0;
}
int pwriteall(int fd, const uint8_t *buf, size_t len, off_t offset)
{
size_t written_bytes = 0;
while (written_bytes < len) {
ssize_t ret;
ret = pwrite(fd, &buf[written_bytes], len - written_bytes, offset);
if (ret < 0) {
if (errno == EINTR)
continue;
u_log_errno("write failed");
return -1;
}
u_assert(ret != 0);
written_bytes += ret;
offset += ret;
}
return 0;
}
int fd_size(int fd, off_t *size_out)
{
u_assert(fd >= 0);
u_assert(size_out);
struct stat s;
if (fstat(fd, &s) < 0) {
u_log_errno("stat failed");
return -1;
}
if (S_ISREG(s.st_mode)) {
*size_out = s.st_size;
} else if (S_ISBLK(s.st_mode)) {
return blockdevice_size(fd, size_out);
} else {
u_log(ERR, "unsupported file type: 0%o", s.st_mode & S_IFMT);
return -1;
}
return 0;
}
time_t time_monotonic(void)
{
struct timespec ts;
u_assert_se(clock_gettime(CLOCK_MONOTONIC, &ts) == 0);
return ts.tv_sec;
}