Coverage Report

Created: 2026-01-16 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/lib/util/sys_rw.c
Line
Count
Source
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
bool sys_valid_io_range(off_t offset, size_t length)
29
0
{
30
0
  uint64_t last_byte_ofs;
31
32
0
  if (offset < 0) {
33
0
    return false;
34
0
  }
35
36
0
  if (offset > INT64_MAX) {
37
0
    return false;
38
0
  }
39
40
0
  if (length > UINT32_MAX) {
41
0
    return false;
42
0
  }
43
44
0
  last_byte_ofs = (uint64_t)offset + (uint64_t)length;
45
0
  if (last_byte_ofs > INT64_MAX) {
46
0
    return false;
47
0
  }
48
49
0
  return true;
50
0
}
51
52
bool sys_io_ranges_overlap(size_t c1, off_t o1,
53
         size_t c2, off_t o2)
54
0
{
55
0
  if (c1 == 0 || c2 == 0) {
56
0
    return false;
57
0
  }
58
0
  if (o2 < o1) {
59
    /*
60
     *          o1
61
     *          |····c1····|
62
     *  o2
63
     *  |····c2···| ?
64
     */
65
0
    return (o2 + c2 > o1);
66
0
  } else {
67
    /*
68
     *  o1
69
     *  |····c1···|
70
     *          o2
71
     *          |····c2····| ?
72
     */
73
0
    return (o1 + c1 > o2);
74
0
  }
75
0
}
76
77
off_t sys_block_align_truncate(off_t len, off_t align)
78
0
{
79
0
  assert(align > 1);
80
0
  assert(((align - 1) & align) == 0);
81
0
  return len & (~align + 1);
82
0
}
83
84
off_t sys_block_align(off_t len, off_t align)
85
0
{
86
0
  assert(align > 1);
87
0
  assert(((align - 1) & align) == 0);
88
0
  return (len + (align - 1)) & ~(align - 1);
89
0
}
90
91
/*******************************************************************
92
A read wrapper that will deal with EINTR/EWOULDBLOCK
93
********************************************************************/
94
95
ssize_t sys_read(int fd, void *buf, size_t count)
96
0
{
97
0
  ssize_t ret;
98
99
0
  do {
100
0
    ret = read(fd, buf, count);
101
0
  } while (ret == -1 && (errno == EINTR || errno == EAGAIN ||
102
0
             errno == EWOULDBLOCK));
103
104
0
  return ret;
105
0
}
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
void sys_read_v(int fd, void *buf, size_t count)
114
0
{
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
ssize_t sys_write(int fd, const void *buf, size_t count)
128
0
{
129
0
  ssize_t ret;
130
131
0
  do {
132
0
    ret = write(fd, buf, count);
133
0
  } while (ret == -1 && (errno == EINTR || errno == EAGAIN ||
134
0
             errno == EWOULDBLOCK));
135
136
0
  return ret;
137
0
}
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
void sys_write_v(int fd, const void *buf, size_t count)
147
0
{
148
0
  ssize_t ret;
149
150
0
  do {
151
0
    ret = write(fd, buf, count);
152
0
  } while (ret == -1 && errno == EINTR);
153
0
}
154
155
156
/*******************************************************************
157
A writev wrapper that will deal with EINTR.
158
********************************************************************/
159
160
ssize_t sys_writev(int fd, const struct iovec *iov, int iovcnt)
161
0
{
162
0
  ssize_t ret;
163
164
0
  do {
165
0
    ret = writev(fd, iov, iovcnt);
166
0
  } while (ret == -1 && (errno == EINTR || errno == EAGAIN ||
167
0
             errno == EWOULDBLOCK));
168
169
0
  return ret;
170
0
}
171
172
/*******************************************************************
173
A pread wrapper that will deal with EINTR
174
********************************************************************/
175
176
ssize_t sys_pread(int fd, void *buf, size_t count, off_t off)
177
0
{
178
0
  ssize_t ret;
179
180
0
  do {
181
0
    ret = pread(fd, buf, count, off);
182
0
  } while (ret == -1 && errno == EINTR);
183
0
  return ret;
184
0
}
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
ssize_t sys_pread_full(int fd, void *buf, size_t count, off_t off)
192
0
{
193
0
  ssize_t total_read = 0;
194
0
  uint8_t *curr_buf = (uint8_t *)buf;
195
0
  size_t curr_count = count;
196
0
  off_t curr_off = off;
197
0
  bool ok;
198
199
0
  ok = sys_valid_io_range(off, count);
200
0
  if (!ok) {
201
0
    errno = EINVAL;
202
0
    return -1;
203
0
  }
204
205
0
  while (curr_count != 0) {
206
0
    ssize_t ret = sys_pread(fd,
207
0
          curr_buf,
208
0
          curr_count,
209
0
          curr_off);
210
211
0
    if (ret == -1) {
212
0
      return -1;
213
0
    }
214
0
    if (ret == 0) {
215
      /* EOF */
216
0
      break;
217
0
    }
218
219
0
    if (ret > curr_count) {
220
0
      errno = EIO;
221
0
      return -1;
222
0
    }
223
224
0
    curr_buf += ret;
225
0
    curr_count -= ret;
226
0
    curr_off += ret;
227
228
0
    total_read += ret;
229
0
  }
230
231
0
  return total_read;
232
0
}
233
234
/*******************************************************************
235
A write wrapper that will deal with EINTR
236
********************************************************************/
237
238
ssize_t sys_pwrite(int fd, const void *buf, size_t count, off_t off)
239
0
{
240
0
  ssize_t ret;
241
242
0
  do {
243
0
    ret = pwrite(fd, buf, count, off);
244
0
  } while (ret == -1 && errno == EINTR);
245
0
  return ret;
246
0
}
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
ssize_t sys_pwrite_full(int fd, const void *buf, size_t count, off_t off)
254
0
{
255
0
  ssize_t total_written = 0;
256
0
  const uint8_t *curr_buf = (const uint8_t *)buf;
257
0
  size_t curr_count = count;
258
0
  off_t curr_off = off;
259
0
  bool ok;
260
261
0
  ok = sys_valid_io_range(off, count);
262
0
  if (!ok) {
263
0
    errno = EINVAL;
264
0
    return -1;
265
0
  }
266
267
0
  while (curr_count != 0) {
268
0
    ssize_t ret = sys_pwrite(fd,
269
0
           curr_buf,
270
0
           curr_count,
271
0
           curr_off);
272
273
0
    if (ret == -1) {
274
0
      return -1;
275
0
    }
276
0
    if (ret == 0) {
277
      /* Ensure we can never spin. */
278
0
      errno = ENOSPC;
279
0
      return -1;
280
0
    }
281
282
0
    if (ret > curr_count) {
283
0
      errno = EIO;
284
0
      return -1;
285
0
    }
286
287
0
    curr_buf += ret;
288
0
    curr_count -= ret;
289
0
    curr_off += ret;
290
291
0
    total_written += ret;
292
0
  }
293
294
0
  return total_written;
295
0
}
296
297
/*******************************************************************
298
 A write wrapper that will deal with EINTR and never allow a short
299
 write unless the file system returns an error.
300
********************************************************************/
301
302
ssize_t sys_write_full(int fd, const void *buf, size_t count)
303
0
{
304
0
  ssize_t total_written = 0;
305
0
  const uint8_t *curr_buf = (const uint8_t *)buf;
306
0
  size_t curr_count = count;
307
308
0
  while (curr_count != 0) {
309
0
    ssize_t ret = sys_write(fd,
310
0
          curr_buf,
311
0
          curr_count);
312
0
    if (ret == -1) {
313
0
      return -1;
314
0
    }
315
0
    if (ret == 0) {
316
      /* Ensure we can never spin. */
317
0
      errno = ENOSPC;
318
0
      return -1;
319
0
    }
320
321
0
    if (ret > curr_count) {
322
0
      errno = EIO;
323
0
      return -1;
324
0
    }
325
326
0
    curr_buf += ret;
327
0
    curr_count -= ret;
328
329
0
    total_written += ret;
330
0
  }
331
332
0
  return total_written;
333
0
}