MCPcopy Create free account
hub / github.com/DeusData/codebase-memory-mcp / config_write_atomic

Function config_write_atomic

src/ui/config.c:235–291  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

233}
234
235static bool config_write_atomic(const char *path, const char *json, size_t json_length) {
236 wchar_t *wide_path = cbm_path_to_wide(path);
237 if (!wide_path) {
238 return false;
239 }
240 size_t temporary_capacity = wcslen(wide_path) + 40U;
241 wchar_t *temporary = calloc(temporary_capacity, sizeof(*temporary));
242 HANDLE file = INVALID_HANDLE_VALUE;
243 if (temporary) {
244 for (unsigned int attempt = 0; attempt < 128U; attempt++) {
245 ULONG sequence = (ULONG)InterlockedIncrement(&g_config_temp_sequence);
246 int written = swprintf(temporary, temporary_capacity, L"%ls.tmp.%08lX.%08lX", wide_path,
247 (unsigned long)GetCurrentProcessId(), (unsigned long)sequence);
248 if (written <= 0 || (size_t)written >= temporary_capacity) {
249 break;
250 }
251 /* DELETE access on the temp handle is what permits the
252 * rename-by-handle publish below. */
253 file = CreateFileW(temporary, GENERIC_WRITE | DELETE, 0, NULL, CREATE_NEW,
254 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH, NULL);
255 if (file != INVALID_HANDLE_VALUE || GetLastError() != ERROR_FILE_EXISTS) {
256 break;
257 }
258 }
259 }
260 bool ok = file != INVALID_HANDLE_VALUE;
261 size_t offset = 0;
262 while (ok && offset < json_length) {
263 size_t remaining = json_length - offset;
264 DWORD chunk = remaining > UINT32_MAX ? UINT32_MAX : (DWORD)remaining;
265 DWORD written = 0;
266 ok = WriteFile(file, json + offset, chunk, &written, NULL) != 0 && written > 0;
267 offset += written;
268 }
269 if (ok) {
270 ok = FlushFileBuffers(file) != 0;
271 }
272 bool published = ok && config_posix_rename_handle(file, wide_path);
273 if (file != INVALID_HANDLE_VALUE && !CloseHandle(file)) {
274 ok = false;
275 }
276 if (ok && !published) {
277 /* Error-driven fallback, not a version probe: POSIX rename needs
278 * NTFS-class filesystem support, so exFAT/SMB-homed configs land
279 * here, keeping the pre-POSIX behavior (replace can fail while a
280 * reader holds the destination open). */
281 published = MoveFileExW(temporary, wide_path,
282 MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH) != 0;
283 }
284 ok = ok && published;
285 if (!ok && temporary) {
286 (void)DeleteFileW(temporary);
287 }
288 free(temporary);
289 free(wide_path);
290 return ok;
291}
292#else

Callers 1

cbm_ui_config_saveFunction · 0.85

Calls 7

cbm_path_to_wideFunction · 0.85
cbm_mkstempFunction · 0.85
config_write_allFunction · 0.85
config_sync_descriptorFunction · 0.85
cbm_unlinkFunction · 0.85

Tested by

no test coverage detected