Skip to content
Bitcoin Roots

v31.1-roots.1 · Commit 7: [PATCH 07/17] feat(rpc): preserve Roots operator interfaces on v31

src/util/fs_helpers.cpp

Before: src/util/fs_helpers.cpp · After: src/util/fs_helpers.cpp

File metadata
index a4d5e40d5f6660a656edc06148e80a154866664c..346b94b320c2f6f40f579d11b94234eae7e813cc 100644

Download original patch · Release notes

Diff rows 1–130 of 130. Line numbers refer to the original before/after files.

+ Added− RemovedUnmarked lines are context.

Scroll the code area horizontally to read long lines. The two line-number columns refer to before and after.

src/util/fs_helpers.cpp CHANGED
@@ -10,12 +10,16 @@
10
10
  #include <random.h>
11
11
  #include <sync.h>
12
12
  #include <tinyformat.h>
13
+ #include <util/check.h>
13
14
  #include <util/fs.h>
14
15
  #include <util/log.h>
15
16
  #include <util/syserror.h>
16
17
 
17
18
  #include <cerrno>
19
+ #include <cstdint>
20
+ #include <cstring>
18
21
  #include <fstream>
22
+ #include <limits>
19
23
  #include <map>
20
24
  #include <memory>
21
25
  #include <optional>
@@ -158,19 +162,35 @@ bool TruncateFile(FILE* file, unsigned int length)
158
162
  */
159
163
  int RaiseFileDescriptorLimit(int nMinFD)
160
164
  {
165
+ Assert(nMinFD >= 0);
161
166
  #if defined(WIN32)
162
167
  return 2048;
163
168
  #else
164
169
  struct rlimit limitFD;
165
170
  if (getrlimit(RLIMIT_NOFILE, &limitFD) != -1) {
166
- if (limitFD.rlim_cur < (rlim_t)nMinFD) {
167
- limitFD.rlim_cur = nMinFD;
168
- if (limitFD.rlim_cur > limitFD.rlim_max)
171
+ // If the current soft limit is already higher, don't raise it
172
+ if (limitFD.rlim_cur != RLIM_INFINITY && std::cmp_less(limitFD.rlim_cur, nMinFD)) {
173
+ const auto current_limit{limitFD.rlim_cur};
174
+ limitFD.rlim_cur = std::in_range<rlim_t>(nMinFD) ? static_cast<rlim_t>(nMinFD) : limitFD.rlim_max;
175
+ // Don't raise soft limit beyond hard limit
176
+ if (limitFD.rlim_max != RLIM_INFINITY && limitFD.rlim_cur > limitFD.rlim_max) {
169
177
  limitFD.rlim_cur = limitFD.rlim_max;
170
- setrlimit(RLIMIT_NOFILE, &limitFD);
171
- getrlimit(RLIMIT_NOFILE, &limitFD);
178
+ }
179
+ if (current_limit != limitFD.rlim_cur) {
180
+ setrlimit(RLIMIT_NOFILE, &limitFD);
181
+ getrlimit(RLIMIT_NOFILE, &limitFD);
182
+ }
172
183
  }
173
- return limitFD.rlim_cur;
184
+ // Check the (possibly raised) current soft limit against the special
185
+ // value of RLIM_INFINITY. Some platforms implement this as the maximum
186
+ // uint64, others as int64 (-1). Avoid casting even if the return type
187
+ // is changed to uint64_t. We also cap unlikely but possible values
188
+ // that would overflow int.
189
+ if (limitFD.rlim_cur == RLIM_INFINITY ||
190
+ std::cmp_greater_equal(limitFD.rlim_cur, std::numeric_limits<int>::max())) {
191
+ return std::numeric_limits<int>::max();
192
+ }
193
+ return static_cast<int>(limitFD.rlim_cur);
174
194
  }
175
195
  return nMinFD; // getrlimit failed, assume it's fine
176
196
  #endif
@@ -178,7 +198,7 @@ int RaiseFileDescriptorLimit(int nMinFD)
178
198
 
179
199
  /**
180
200
  * this function tries to make a particular range of a file allocated (corresponding to disk space)
181
- * it is advisory, and the range specified in the arguments will never contain live data
201
+ * It is advisory and must preserve existing bytes in the requested range.
182
202
  */
183
203
  void AllocateFileRange(FILE* file, unsigned int offset, unsigned int length)
184
204
  {
@@ -187,42 +207,43 @@ void AllocateFileRange(FILE* file, unsigned int offset, unsigned int length)
187
207
  HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file));
188
208
  LARGE_INTEGER nFileSize;
189
209
  int64_t nEndPos = (int64_t)offset + length;
190
- nFileSize.u.LowPart = nEndPos & 0xFFFFFFFF;
191
- nFileSize.u.HighPart = nEndPos >> 32;
192
- SetFilePointerEx(hFile, nFileSize, 0, FILE_BEGIN);
193
- SetEndOfFile(hFile);
194
- #elif defined(__APPLE__)
195
- // OSX specific version
196
- // NOTE: Contrary to other OS versions, the OSX version assumes that
197
- // NOTE: offset is the size of the file.
198
- fstore_t fst;
199
- fst.fst_flags = F_ALLOCATECONTIG;
200
- fst.fst_posmode = F_PEOFPOSMODE;
201
- fst.fst_offset = 0;
202
- fst.fst_length = length; // mac os fst_length takes the # of free bytes to allocate, not desired file size
203
- fst.fst_bytesalloc = 0;
204
- if (fcntl(fileno(file), F_PREALLOCATE, &fst) == -1) {
205
- fst.fst_flags = F_ALLOCATEALL;
206
- fcntl(fileno(file), F_PREALLOCATE, &fst);
210
+ if (GetFileSizeEx(hFile, &nFileSize) && nFileSize.QuadPart < nEndPos) {
211
+ nFileSize.u.LowPart = nEndPos & 0xFFFFFFFF;
212
+ nFileSize.u.HighPart = nEndPos >> 32;
213
+ if (SetFilePointerEx(hFile, nFileSize, 0, FILE_BEGIN)) {
214
+ SetEndOfFile(hFile);
215
+ }
207
216
  }
208
- ftruncate(fileno(file), static_cast<off_t>(offset) + length);
209
217
  #else
210
218
  #if defined(HAVE_POSIX_FALLOCATE)
211
219
  // Version using posix_fallocate
212
- off_t nEndPos = (off_t)offset + length;
213
- if (0 == posix_fallocate(fileno(file), 0, nEndPos)) return;
220
+ if (0 == posix_fallocate(fileno(file), offset, length)) return;
214
221
  #endif
215
222
  // Fallback version
216
223
  // TODO: just write one byte per block
217
- static const char buf[65536] = {};
224
+ uint8_t buf[65536];
218
225
  if (fseek(file, offset, SEEK_SET)) {
219
226
  return;
220
227
  }
228
+ clearerr(file);
221
229
  while (length > 0) {
222
230
  unsigned int now = 65536;
223
231
  if (length < now)
224
232
  now = length;
225
- fwrite(buf, 1, now, file); // allowed to fail; this function is advisory anyway
233
+ const size_t rlen = fread(buf, 1, now, file);
234
+ if (rlen < now) {
235
+ if (ferror(file)) {
236
+ // Don't clobber anything, just give up
237
+ clearerr(file);
238
+ return;
239
+ }
240
+ memset(&buf[rlen], 0, now - rlen);
241
+ }
242
+ // Rewind after every read so allocation preserves existing bytes.
243
+ if (fseek(file, -static_cast<long>(rlen), SEEK_CUR)) return;
244
+ if (fwrite(buf, 1, now, file) != now) return; // Advisory allocation may fail.
245
+ // An update stream needs a positioning operation between writing and reading.
246
+ if (fseek(file, 0, SEEK_CUR)) return;
226
247
  length -= now;
227
248
  }
228
249
  #endif