]> git.proxmox.com Git - ceph.git/blob - ceph/src/common/safe_io.c
import ceph 14.2.5
[ceph.git] / ceph / src / common / safe_io.c
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2011 New Dream Network
7 *
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
12 *
13 */
14
15 #include "common/safe_io.h"
16 #include "include/compat.h"
17
18 #include <stdio.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <limits.h>
24
25 ssize_t safe_read(int fd, void *buf, size_t count)
26 {
27 size_t cnt = 0;
28
29 while (cnt < count) {
30 ssize_t r = read(fd, buf, count - cnt);
31 if (r <= 0) {
32 if (r == 0) {
33 // EOF
34 return cnt;
35 }
36 if (errno == EINTR)
37 continue;
38 return -errno;
39 }
40 cnt += r;
41 buf = (char *)buf + r;
42 }
43 return cnt;
44 }
45
46 ssize_t safe_read_exact(int fd, void *buf, size_t count)
47 {
48 ssize_t ret = safe_read(fd, buf, count);
49 if (ret < 0)
50 return ret;
51 if ((size_t)ret != count)
52 return -EDOM;
53 return 0;
54 }
55
56 ssize_t safe_write(int fd, const void *buf, size_t count)
57 {
58 while (count > 0) {
59 ssize_t r = write(fd, buf, count);
60 if (r < 0) {
61 if (errno == EINTR)
62 continue;
63 return -errno;
64 }
65 count -= r;
66 buf = (char *)buf + r;
67 }
68 return 0;
69 }
70
71 ssize_t safe_pread(int fd, void *buf, size_t count, off_t offset)
72 {
73 size_t cnt = 0;
74 char *b = (char*)buf;
75
76 while (cnt < count) {
77 ssize_t r = pread(fd, b + cnt, count - cnt, offset + cnt);
78 if (r <= 0) {
79 if (r == 0) {
80 // EOF
81 return cnt;
82 }
83 if (errno == EINTR)
84 continue;
85 return -errno;
86 }
87
88 cnt += r;
89 }
90 return cnt;
91 }
92
93 ssize_t safe_pread_exact(int fd, void *buf, size_t count, off_t offset)
94 {
95 ssize_t ret = safe_pread(fd, buf, count, offset);
96 if (ret < 0)
97 return ret;
98 if ((size_t)ret != count)
99 return -EDOM;
100 return 0;
101 }
102
103 ssize_t safe_pwrite(int fd, const void *buf, size_t count, off_t offset)
104 {
105 while (count > 0) {
106 ssize_t r = pwrite(fd, buf, count, offset);
107 if (r < 0) {
108 if (errno == EINTR)
109 continue;
110 return -errno;
111 }
112 count -= r;
113 buf = (char *)buf + r;
114 offset += r;
115 }
116 return 0;
117 }
118
119 #ifdef CEPH_HAVE_SPLICE
120 ssize_t safe_splice(int fd_in, off_t *off_in, int fd_out, off_t *off_out,
121 size_t len, unsigned int flags)
122 {
123 size_t cnt = 0;
124
125 while (cnt < len) {
126 ssize_t r = splice(fd_in, off_in, fd_out, off_out, len - cnt, flags);
127 if (r <= 0) {
128 if (r == 0) {
129 // EOF
130 return cnt;
131 }
132 if (errno == EINTR)
133 continue;
134 if (errno == EAGAIN)
135 break;
136 return -errno;
137 }
138 cnt += r;
139 }
140 return cnt;
141 }
142
143 ssize_t safe_splice_exact(int fd_in, off_t *off_in, int fd_out,
144 off_t *off_out, size_t len, unsigned int flags)
145 {
146 ssize_t ret = safe_splice(fd_in, off_in, fd_out, off_out, len, flags);
147 if (ret < 0)
148 return ret;
149 if ((size_t)ret != len)
150 return -EDOM;
151 return 0;
152 }
153 #endif
154
155 int safe_write_file(const char *base, const char *file,
156 const char *val, size_t vallen,
157 unsigned mode)
158 {
159 int ret;
160 char fn[PATH_MAX];
161 char tmp[PATH_MAX];
162 int fd;
163
164 // does the file already have correct content?
165 char oldval[80];
166 ret = safe_read_file(base, file, oldval, sizeof(oldval));
167 if (ret == (int)vallen && memcmp(oldval, val, vallen) == 0)
168 return 0; // yes.
169
170 snprintf(fn, sizeof(fn), "%s/%s", base, file);
171 snprintf(tmp, sizeof(tmp), "%s/%s.tmp", base, file);
172 fd = open(tmp, O_WRONLY|O_CREAT|O_TRUNC, mode);
173 if (fd < 0) {
174 ret = errno;
175 return -ret;
176 }
177 ret = safe_write(fd, val, vallen);
178 if (ret) {
179 VOID_TEMP_FAILURE_RETRY(close(fd));
180 return ret;
181 }
182
183 ret = fsync(fd);
184 if (ret < 0) ret = -errno;
185 VOID_TEMP_FAILURE_RETRY(close(fd));
186 if (ret < 0) {
187 unlink(tmp);
188 return ret;
189 }
190 ret = rename(tmp, fn);
191 if (ret < 0) {
192 ret = -errno;
193 unlink(tmp);
194 return ret;
195 }
196
197 fd = open(base, O_RDONLY);
198 if (fd < 0) {
199 ret = -errno;
200 return ret;
201 }
202 ret = fsync(fd);
203 if (ret < 0) ret = -errno;
204 VOID_TEMP_FAILURE_RETRY(close(fd));
205
206 return ret;
207 }
208
209 int safe_read_file(const char *base, const char *file,
210 char *val, size_t vallen)
211 {
212 char fn[PATH_MAX];
213 int fd, len;
214
215 snprintf(fn, sizeof(fn), "%s/%s", base, file);
216 fd = open(fn, O_RDONLY);
217 if (fd < 0) {
218 return -errno;
219 }
220 len = safe_read(fd, val, vallen);
221 if (len < 0) {
222 VOID_TEMP_FAILURE_RETRY(close(fd));
223 return len;
224 }
225 // close sometimes returns errors, but only after write()
226 VOID_TEMP_FAILURE_RETRY(close(fd));
227
228 return len;
229 }