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. Before is on the left; after is on the right. Unified view fits narrow screens more easily.

src/util/fs_helpers.cpp CHANGED
@@ -10,12 +10,16 @@
10
  #include <random.h>
11
  #include <sync.h>
12
  #include <tinyformat.h>
 
13
  #include <util/fs.h>
14
  #include <util/log.h>
15
  #include <util/syserror.h>
16
 
17
  #include <cerrno>
 
 
18
  #include <fstream>
 
19
  #include <map>
20
  #include <memory>
21
  #include <optional>
@@ -158,19 +162,35 @@ bool TruncateFile(FILE* file, unsigned int length)
158
  */
159
  int RaiseFileDescriptorLimit(int nMinFD)
160
  {
 
161
  #if defined(WIN32)
162
  return 2048;
163
  #else
164
  struct rlimit limitFD;
165
  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)
 
 
 
169
  limitFD.rlim_cur = limitFD.rlim_max;
170
- setrlimit(RLIMIT_NOFILE, &limitFD);
171
- getrlimit(RLIMIT_NOFILE, &limitFD);
 
 
 
172
  }
173
- return limitFD.rlim_cur;
 
 
 
 
 
 
 
 
 
174
  }
175
  return nMinFD; // getrlimit failed, assume it's fine
176
  #endif
@@ -178,7 +198,7 @@ int RaiseFileDescriptorLimit(int nMinFD)
178
 
179
  /**
180
  * 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
182
  */
183
  void AllocateFileRange(FILE* file, unsigned int offset, unsigned int length)
184
  {
@@ -187,42 +207,43 @@ void AllocateFileRange(FILE* file, unsigned int offset, unsigned int length)
187
  HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file));
188
  LARGE_INTEGER nFileSize;
189
  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);
207
  }
208
- ftruncate(fileno(file), static_cast<off_t>(offset) + length);
209
  #else
210
  #if defined(HAVE_POSIX_FALLOCATE)
211
  // Version using posix_fallocate
212
- off_t nEndPos = (off_t)offset + length;
213
- if (0 == posix_fallocate(fileno(file), 0, nEndPos)) return;
214
  #endif
215
  // Fallback version
216
  // TODO: just write one byte per block
217
- static const char buf[65536] = {};
218
  if (fseek(file, offset, SEEK_SET)) {
219
  return;
220
  }
 
221
  while (length > 0) {
222
  unsigned int now = 65536;
223
  if (length < now)
224
  now = length;
225
- fwrite(buf, 1, now, file); // allowed to fail; this function is advisory anyway
 
 
 
 
 
 
 
 
 
 
 
 
 
226
  length -= now;
227
  }
228
  #endif
 
10
  #include <random.h>
11
  #include <sync.h>
12
  #include <tinyformat.h>
13
+ #include <util/check.h>
14
  #include <util/fs.h>
15
  #include <util/log.h>
16
  #include <util/syserror.h>
17
 
18
  #include <cerrno>
19
+ #include <cstdint>
20
+ #include <cstring>
21
  #include <fstream>
22
+ #include <limits>
23
  #include <map>
24
  #include <memory>
25
  #include <optional>
 
162
  */
163
  int RaiseFileDescriptorLimit(int nMinFD)
164
  {
165
+ Assert(nMinFD >= 0);
166
  #if defined(WIN32)
167
  return 2048;
168
  #else
169
  struct rlimit limitFD;
170
  if (getrlimit(RLIMIT_NOFILE, &limitFD) != -1) {
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) {
177
  limitFD.rlim_cur = limitFD.rlim_max;
178
+ }
179
+ if (current_limit != limitFD.rlim_cur) {
180
+ setrlimit(RLIMIT_NOFILE, &limitFD);
181
+ getrlimit(RLIMIT_NOFILE, &limitFD);
182
+ }
183
  }
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);
194
  }
195
  return nMinFD; // getrlimit failed, assume it's fine
196
  #endif
 
198
 
199
  /**
200
  * this function tries to make a particular range of a file allocated (corresponding to disk space)
201
+ * It is advisory and must preserve existing bytes in the requested range.
202
  */
203
  void AllocateFileRange(FILE* file, unsigned int offset, unsigned int length)
204
  {
 
207
  HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file));
208
  LARGE_INTEGER nFileSize;
209
  int64_t nEndPos = (int64_t)offset + length;
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
+ }
 
 
 
 
 
 
 
 
 
 
 
216
  }
 
217
  #else
218
  #if defined(HAVE_POSIX_FALLOCATE)
219
  // Version using posix_fallocate
220
+ if (0 == posix_fallocate(fileno(file), offset, length)) return;
 
221
  #endif
222
  // Fallback version
223
  // TODO: just write one byte per block
224
+ uint8_t buf[65536];
225
  if (fseek(file, offset, SEEK_SET)) {
226
  return;
227
  }
228
+ clearerr(file);
229
  while (length > 0) {
230
  unsigned int now = 65536;
231
  if (length < now)
232
  now = length;
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;
247
  length -= now;
248
  }
249
  #endif