]> git.proxmox.com Git - ceph.git/blame - ceph/src/common/safe_io.c
update sources to v12.1.0
[ceph.git] / ceph / src / common / safe_io.c
CommitLineData
7c673cae
FG
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
31f18b77
FG
15#include "common/safe_io.h"
16#include "include/compat.h"
17
7c673cae
FG
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
7c673cae
FG
25ssize_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
46ssize_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
56ssize_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
71ssize_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
93ssize_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
103ssize_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
120ssize_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
143ssize_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
155int safe_write_file(const char *base, const char *file,
156 const char *val, size_t vallen)
157{
158 int ret;
159 char fn[PATH_MAX];
160 char tmp[PATH_MAX];
161 int fd;
162
163 // does the file already have correct content?
164 char oldval[80];
165 ret = safe_read_file(base, file, oldval, sizeof(oldval));
166 if (ret == (int)vallen && memcmp(oldval, val, vallen) == 0)
167 return 0; // yes.
168
169 snprintf(fn, sizeof(fn), "%s/%s", base, file);
170 snprintf(tmp, sizeof(tmp), "%s/%s.tmp", base, file);
171 fd = open(tmp, O_WRONLY|O_CREAT|O_TRUNC, 0644);
172 if (fd < 0) {
173 ret = errno;
174 return -ret;
175 }
176 ret = safe_write(fd, val, vallen);
177 if (ret) {
178 VOID_TEMP_FAILURE_RETRY(close(fd));
179 return ret;
180 }
181
182 ret = fsync(fd);
183 if (ret < 0) ret = -errno;
184 VOID_TEMP_FAILURE_RETRY(close(fd));
185 if (ret < 0) {
186 unlink(tmp);
187 return ret;
188 }
189 ret = rename(tmp, fn);
190 if (ret < 0) {
191 ret = -errno;
192 unlink(tmp);
193 return ret;
194 }
195
196 fd = open(base, O_RDONLY);
197 if (fd < 0) {
198 ret = -errno;
199 return ret;
200 }
201 ret = fsync(fd);
202 if (ret < 0) ret = -errno;
203 VOID_TEMP_FAILURE_RETRY(close(fd));
204
205 return ret;
206}
207
208int safe_read_file(const char *base, const char *file,
209 char *val, size_t vallen)
210{
211 char fn[PATH_MAX];
212 int fd, len;
213
214 snprintf(fn, sizeof(fn), "%s/%s", base, file);
215 fd = open(fn, O_RDONLY);
216 if (fd < 0) {
217 return -errno;
218 }
219 len = safe_read(fd, val, vallen);
220 if (len < 0) {
221 VOID_TEMP_FAILURE_RETRY(close(fd));
222 return len;
223 }
224 // close sometimes returns errors, but only after write()
225 VOID_TEMP_FAILURE_RETRY(close(fd));
226
227 return len;
228}