Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / 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 {
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
208 int 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 }