/src/c-blosc2/blosc/blosc2-stdio.c
Line | Count | Source (jump to first uncovered line) |
1 | | /********************************************************************* |
2 | | Blosc - Blocked Shuffling and Compression Library |
3 | | |
4 | | Copyright (c) 2021 Blosc Development Team <blosc@blosc.org> |
5 | | https://blosc.org |
6 | | License: BSD 3-Clause (see LICENSE.txt) |
7 | | |
8 | | See LICENSE.txt for details about copyright and rights to use. |
9 | | **********************************************************************/ |
10 | | |
11 | | #if defined(__linux__) |
12 | | /* Must be defined before anything else is included */ |
13 | | #define _GNU_SOURCE |
14 | | #endif |
15 | | |
16 | | #include "blosc2/blosc2-stdio.h" |
17 | | #include "blosc2.h" |
18 | | |
19 | | #include <stdlib.h> |
20 | | #include <stdio.h> |
21 | | #include <stdint.h> |
22 | | #include <errno.h> |
23 | | #include <inttypes.h> |
24 | | |
25 | | #if defined(_WIN32) |
26 | | #include <memoryapi.h> |
27 | | // See https://github.com/Blosc/python-blosc2/issues/359 |
28 | | #define fseek _fseeki64 |
29 | | #define ftell _ftelli64 |
30 | | #else |
31 | | #include <sys/mman.h> |
32 | | #endif |
33 | | |
34 | | |
35 | 0 | void *blosc2_stdio_open(const char *urlpath, const char *mode, void *params) { |
36 | 0 | BLOSC_UNUSED_PARAM(params); |
37 | 0 | FILE *file = fopen(urlpath, mode); |
38 | 0 | if (file == NULL) |
39 | 0 | return NULL; |
40 | 0 | blosc2_stdio_file *my_fp = malloc(sizeof(blosc2_stdio_file)); |
41 | 0 | my_fp->file = file; |
42 | 0 | return my_fp; |
43 | 0 | } |
44 | | |
45 | 0 | int blosc2_stdio_close(void *stream) { |
46 | 0 | blosc2_stdio_file *my_fp = (blosc2_stdio_file *) stream; |
47 | 0 | int err = fclose(my_fp->file); |
48 | 0 | free(my_fp); |
49 | 0 | return err; |
50 | 0 | } |
51 | | |
52 | 0 | int64_t blosc2_stdio_size(void *stream) { |
53 | 0 | blosc2_stdio_file *my_fp = (blosc2_stdio_file *) stream; |
54 | |
|
55 | 0 | fseek(my_fp->file, 0, SEEK_END); |
56 | 0 | int64_t size = ftell(my_fp->file); |
57 | 0 | fseek(my_fp->file, 0, SEEK_SET); |
58 | |
|
59 | 0 | return size; |
60 | 0 | } |
61 | | |
62 | 0 | int64_t blosc2_stdio_write(const void *ptr, int64_t size, int64_t nitems, int64_t position, void *stream) { |
63 | 0 | blosc2_stdio_file *my_fp = (blosc2_stdio_file *) stream; |
64 | 0 | fseek(my_fp->file, position, SEEK_SET); |
65 | |
|
66 | 0 | size_t nitems_ = fwrite(ptr, (size_t) size, (size_t) nitems, my_fp->file); |
67 | 0 | return (int64_t) nitems_; |
68 | 0 | } |
69 | | |
70 | 0 | int64_t blosc2_stdio_read(void **ptr, int64_t size, int64_t nitems, int64_t position, void *stream) { |
71 | 0 | blosc2_stdio_file *my_fp = (blosc2_stdio_file *) stream; |
72 | 0 | fseek(my_fp->file, position, SEEK_SET); |
73 | |
|
74 | 0 | void* data_ptr = *ptr; |
75 | 0 | size_t nitems_ = fread(data_ptr, (size_t) size, (size_t) nitems, my_fp->file); |
76 | 0 | return (int64_t) nitems_; |
77 | 0 | } |
78 | | |
79 | 0 | int blosc2_stdio_truncate(void *stream, int64_t size) { |
80 | 0 | blosc2_stdio_file *my_fp = (blosc2_stdio_file *) stream; |
81 | 0 | int rc; |
82 | | #if defined(_MSC_VER) |
83 | | rc = _chsize_s(_fileno(my_fp->file), size); |
84 | | #else |
85 | 0 | rc = ftruncate(fileno(my_fp->file), size); |
86 | 0 | #endif |
87 | 0 | return rc; |
88 | 0 | } |
89 | | |
90 | 2.29k | int blosc2_stdio_destroy(void* params) { |
91 | 2.29k | BLOSC_UNUSED_PARAM(params); |
92 | 2.29k | return 0; |
93 | 2.29k | } |
94 | | |
95 | | #if defined(_WIN32) |
96 | | void _print_last_error() { |
97 | | DWORD last_error = GetLastError(); |
98 | | if(last_error == 0) { |
99 | | return; |
100 | | } |
101 | | |
102 | | LPSTR msg = NULL; |
103 | | FormatMessage( |
104 | | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, |
105 | | NULL, |
106 | | last_error, |
107 | | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), |
108 | | (LPSTR)&msg, |
109 | | 0, |
110 | | NULL |
111 | | ); |
112 | | |
113 | | printf("Message for the error %lu:\n%s\n", last_error, msg); |
114 | | LocalFree(msg); |
115 | | } |
116 | | #endif |
117 | | |
118 | 0 | void *blosc2_stdio_mmap_open(const char *urlpath, const char *mode, void* params) { |
119 | 0 | BLOSC_UNUSED_PARAM(mode); |
120 | |
|
121 | 0 | blosc2_stdio_mmap *mmap_file = (blosc2_stdio_mmap *) params; |
122 | 0 | if (mmap_file->addr != NULL) { |
123 | 0 | if (strcmp(mmap_file->urlpath, urlpath) != 0) { |
124 | 0 | BLOSC_TRACE_ERROR( |
125 | 0 | "The memory-mapped file is already opened with the path %s and hence cannot be reopened with the path %s. This " |
126 | 0 | "happens if you try to open a sframe (sparse frame); please note that memory-mapped files are not supported " |
127 | 0 | "for sframes.", |
128 | 0 | mmap_file->urlpath, |
129 | 0 | urlpath |
130 | 0 | ); |
131 | 0 | return NULL; |
132 | 0 | } |
133 | | |
134 | | /* A memory-mapped file is only opened once */ |
135 | 0 | return mmap_file; |
136 | 0 | } |
137 | | |
138 | | // Keep the original path to ensure that all future file openings are with the same path |
139 | 0 | mmap_file->urlpath = malloc(strlen(urlpath) + 1); |
140 | 0 | strcpy(mmap_file->urlpath, urlpath); |
141 | | |
142 | | /* mmap_file->mode mapping is similar to Numpy's memmap |
143 | | (https://github.com/numpy/numpy/blob/main/numpy/_core/memmap.py) and CPython |
144 | | (https://github.com/python/cpython/blob/main/Modules/mmapmodule.c) */ |
145 | | #if defined(_WIN32) |
146 | | char* open_mode; |
147 | | bool use_initial_mapping_size; |
148 | | if (strcmp(mmap_file->mode, "r") == 0) { |
149 | | mmap_file->access_flags = PAGE_READONLY; |
150 | | mmap_file->map_flags = FILE_MAP_READ; |
151 | | mmap_file->is_memory_only = false; |
152 | | open_mode = "rb"; |
153 | | use_initial_mapping_size = false; |
154 | | } else if (strcmp(mmap_file->mode, "r+") == 0) { |
155 | | mmap_file->access_flags = PAGE_READWRITE; |
156 | | mmap_file->map_flags = FILE_MAP_WRITE; |
157 | | mmap_file->is_memory_only = false; |
158 | | open_mode = "rb+"; |
159 | | use_initial_mapping_size = true; |
160 | | } else if (strcmp(mmap_file->mode, "w+") == 0) { |
161 | | mmap_file->access_flags = PAGE_READWRITE; |
162 | | mmap_file->map_flags = FILE_MAP_WRITE; |
163 | | mmap_file->is_memory_only = false; |
164 | | open_mode = "wb+"; |
165 | | use_initial_mapping_size = true; |
166 | | } else if (strcmp(mmap_file->mode, "c") == 0) { |
167 | | mmap_file->access_flags = PAGE_WRITECOPY; |
168 | | mmap_file->map_flags = FILE_MAP_COPY; |
169 | | mmap_file->is_memory_only = true; |
170 | | open_mode = "rb"; |
171 | | use_initial_mapping_size = false; |
172 | | } else { |
173 | | BLOSC_TRACE_ERROR("Mode %s not supported for memory-mapped files.", mmap_file->mode); |
174 | | return NULL; |
175 | | } |
176 | | #else |
177 | 0 | char* open_mode; |
178 | 0 | bool use_initial_mapping_size; |
179 | 0 | if (strcmp(mmap_file->mode, "r") == 0) { |
180 | 0 | mmap_file->access_flags = PROT_READ; |
181 | 0 | mmap_file->map_flags = MAP_SHARED; |
182 | 0 | mmap_file->is_memory_only = false; |
183 | 0 | open_mode = "rb"; |
184 | 0 | use_initial_mapping_size = false; |
185 | 0 | } else if (strcmp(mmap_file->mode, "r+") == 0) { |
186 | 0 | mmap_file->access_flags = PROT_READ | PROT_WRITE; |
187 | 0 | mmap_file->map_flags = MAP_SHARED; |
188 | 0 | mmap_file->is_memory_only = false; |
189 | 0 | open_mode = "rb+"; |
190 | 0 | use_initial_mapping_size = true; |
191 | 0 | } else if (strcmp(mmap_file->mode, "w+") == 0) { |
192 | 0 | mmap_file->access_flags = PROT_READ | PROT_WRITE; |
193 | 0 | mmap_file->map_flags = MAP_SHARED; |
194 | 0 | mmap_file->is_memory_only = false; |
195 | 0 | open_mode = "wb+"; |
196 | 0 | use_initial_mapping_size = true; |
197 | 0 | } else if (strcmp(mmap_file->mode, "c") == 0) { |
198 | 0 | mmap_file->access_flags = PROT_READ | PROT_WRITE; |
199 | 0 | mmap_file->map_flags = MAP_PRIVATE; |
200 | 0 | mmap_file->is_memory_only = true; |
201 | 0 | open_mode = "rb"; |
202 | 0 | use_initial_mapping_size = true; |
203 | 0 | } else { |
204 | 0 | BLOSC_TRACE_ERROR("Mode %s not supported for memory-mapped files.", mmap_file->mode); |
205 | 0 | return NULL; |
206 | 0 | } |
207 | 0 | #endif |
208 | | |
209 | 0 | mmap_file->file = fopen(urlpath, open_mode); |
210 | 0 | if (mmap_file->file == NULL) { |
211 | 0 | BLOSC_TRACE_ERROR("Cannot open the file %s with mode %s.", urlpath, open_mode); |
212 | 0 | return NULL; |
213 | 0 | } |
214 | | |
215 | | /* Retrieve the size of the file */ |
216 | 0 | fseek(mmap_file->file, 0, SEEK_END); |
217 | 0 | mmap_file->file_size = ftell(mmap_file->file); |
218 | 0 | fseek(mmap_file->file, 0, SEEK_SET); |
219 | | |
220 | | /* The size of the mapping must be > 0 so we are using a large enough buffer for writing |
221 | | (which will be increased later if needed) */ |
222 | 0 | if (use_initial_mapping_size) { |
223 | 0 | mmap_file->mapping_size = mmap_file->initial_mapping_size; |
224 | 0 | } |
225 | 0 | else { |
226 | 0 | mmap_file->mapping_size = mmap_file->file_size; |
227 | 0 | } |
228 | |
|
229 | 0 | if (mmap_file->file_size > mmap_file->mapping_size) { |
230 | 0 | mmap_file->mapping_size = mmap_file->file_size; |
231 | 0 | } |
232 | |
|
233 | | #if defined(_WIN32) |
234 | | mmap_file->fd = _fileno(mmap_file->file); |
235 | | |
236 | | /* Windows automatically expands the file size to the memory mapped file |
237 | | (https://learn.microsoft.com/en-us/windows/win32/memory/creating-a-file-mapping-object). |
238 | | In general, the size of the file is directly connected to the size of the mapping and cannot change. We cut the |
239 | | file size to the target size in the end after we close the mapping */ |
240 | | HANDLE file_handle = (HANDLE) _get_osfhandle(mmap_file->fd); |
241 | | DWORD size_hi = (DWORD)(mmap_file->mapping_size >> 32); |
242 | | DWORD size_lo = (DWORD)(mmap_file->mapping_size & 0xFFFFFFFF); |
243 | | mmap_file->mmap_handle = CreateFileMapping(file_handle, NULL, mmap_file->access_flags, size_hi, size_lo, NULL); |
244 | | if (mmap_file->mmap_handle == NULL) { |
245 | | _print_last_error(); |
246 | | BLOSC_TRACE_ERROR("Creating the memory mapping failed for the file %s.", urlpath); |
247 | | return NULL; |
248 | | } |
249 | | |
250 | | DWORD offset = 0; |
251 | | mmap_file->addr = (char*) MapViewOfFile( |
252 | | mmap_file->mmap_handle, mmap_file->map_flags, offset, offset, mmap_file->mapping_size); |
253 | | if (mmap_file->addr == NULL) { |
254 | | _print_last_error(); |
255 | | BLOSC_TRACE_ERROR("Memory mapping failed for the file %s.", urlpath); |
256 | | |
257 | | if (!CloseHandle(mmap_file->mmap_handle)) { |
258 | | _print_last_error(); |
259 | | BLOSC_TRACE_ERROR("Cannot close the handle to the memory-mapped file."); |
260 | | } |
261 | | |
262 | | return NULL; |
263 | | } |
264 | | #else |
265 | 0 | mmap_file->fd = fileno(mmap_file->file); |
266 | | |
267 | | /* Offset where the mapping should start */ |
268 | 0 | int64_t offset = 0; |
269 | 0 | mmap_file->addr = mmap( |
270 | 0 | NULL, mmap_file->mapping_size, mmap_file->access_flags, mmap_file->map_flags, mmap_file->fd, offset); |
271 | 0 | if (mmap_file->addr == MAP_FAILED) { |
272 | 0 | BLOSC_TRACE_ERROR("Memory mapping failed for file %s (error: %s).", urlpath, strerror(errno)); |
273 | 0 | return NULL; |
274 | 0 | } |
275 | 0 | #endif |
276 | | |
277 | 0 | BLOSC_INFO( |
278 | 0 | "Opened memory-mapped file %s in mode %s with an mapping size of %" PRId64 " bytes.", |
279 | 0 | mmap_file->urlpath, |
280 | 0 | mmap_file->mode, |
281 | 0 | mmap_file->mapping_size |
282 | 0 | ); |
283 | | |
284 | | /* The mmap_file->mode parameter is only available during the opening call and cannot be used in any of the other |
285 | | I/O functions since this string is managed by the caller (e.g., from Python) and the memory of the string may not |
286 | | be available anymore at a later point. */ |
287 | 0 | mmap_file->mode = NULL; |
288 | |
|
289 | 0 | return mmap_file; |
290 | 0 | } |
291 | | |
292 | 0 | int blosc2_stdio_mmap_close(void *stream) { |
293 | 0 | BLOSC_UNUSED_PARAM(stream); |
294 | 0 | return 0; |
295 | 0 | } |
296 | | |
297 | 0 | int64_t blosc2_stdio_mmap_size(void *stream) { |
298 | 0 | blosc2_stdio_mmap *mmap_file = (blosc2_stdio_mmap *) stream; |
299 | 0 | return mmap_file->file_size; |
300 | 0 | } |
301 | | |
302 | 0 | int64_t blosc2_stdio_mmap_write(const void *ptr, int64_t size, int64_t nitems, int64_t position, void *stream) { |
303 | 0 | blosc2_stdio_mmap *mmap_file = (blosc2_stdio_mmap *) stream; |
304 | |
|
305 | 0 | if (position < 0) { |
306 | 0 | BLOSC_TRACE_ERROR("Cannot write to a negative position."); |
307 | 0 | return 0; |
308 | 0 | } |
309 | | |
310 | 0 | int64_t n_bytes = size * nitems; |
311 | 0 | if (n_bytes == 0) { |
312 | 0 | return 0; |
313 | 0 | } |
314 | | |
315 | 0 | int64_t position_end = position + n_bytes; |
316 | 0 | int64_t new_size = position_end > mmap_file->file_size ? position_end : mmap_file->file_size; |
317 | |
|
318 | | #if defined(_WIN32) |
319 | | if (mmap_file->file_size < new_size) { |
320 | | mmap_file->file_size = new_size; |
321 | | } |
322 | | |
323 | | if (mmap_file->mapping_size < mmap_file->file_size) { |
324 | | mmap_file->mapping_size = mmap_file->file_size * 2; |
325 | | |
326 | | /* We need to remap the file completely and cannot pass the previous used address on Windows */ |
327 | | if (!UnmapViewOfFile(mmap_file->addr)) { |
328 | | _print_last_error(); |
329 | | BLOSC_TRACE_ERROR("Cannot unmap the memory-mapped file."); |
330 | | return 0; |
331 | | } |
332 | | if (!CloseHandle(mmap_file->mmap_handle)) { |
333 | | _print_last_error(); |
334 | | BLOSC_TRACE_ERROR("Cannot close the handle to the memory-mapped file."); |
335 | | return 0; |
336 | | } |
337 | | |
338 | | HANDLE file_handle = (HANDLE) _get_osfhandle(mmap_file->fd); |
339 | | DWORD size_hi = (DWORD)(mmap_file->mapping_size >> 32); |
340 | | DWORD size_lo = (DWORD)(mmap_file->mapping_size & 0xFFFFFFFF); |
341 | | mmap_file->mmap_handle = CreateFileMapping(file_handle, NULL, mmap_file->access_flags, size_hi, size_lo, NULL); |
342 | | if (mmap_file->mmap_handle == NULL) { |
343 | | _print_last_error(); |
344 | | BLOSC_TRACE_ERROR("Cannot remapt the memory-mapped file."); |
345 | | return 0; |
346 | | } |
347 | | |
348 | | DWORD offset = 0; |
349 | | char* new_address = (char*) MapViewOfFile( |
350 | | mmap_file->mmap_handle, mmap_file->map_flags, offset, offset, mmap_file->mapping_size); |
351 | | if (new_address == NULL) { |
352 | | _print_last_error(); |
353 | | BLOSC_TRACE_ERROR("Cannot remapt the memory-mapped file"); |
354 | | |
355 | | if (!CloseHandle(mmap_file->mmap_handle)) { |
356 | | _print_last_error(); |
357 | | BLOSC_TRACE_ERROR("Cannot close the handle to the memory-mapped file."); |
358 | | } |
359 | | |
360 | | return 0; |
361 | | } |
362 | | |
363 | | mmap_file->addr = new_address; |
364 | | } |
365 | | #else |
366 | 0 | if (mmap_file->file_size < new_size) { |
367 | 0 | mmap_file->file_size = new_size; |
368 | |
|
369 | 0 | if (!mmap_file->is_memory_only) { |
370 | 0 | int rc = ftruncate(mmap_file->fd, new_size); |
371 | 0 | if (rc < 0) { |
372 | 0 | BLOSC_TRACE_ERROR("Cannot extend the file size to %" PRId64 " bytes (error: %s).", new_size, strerror(errno)); |
373 | 0 | return 0; |
374 | 0 | } |
375 | 0 | } |
376 | 0 | } |
377 | | |
378 | 0 | if (mmap_file->mapping_size < mmap_file->file_size) { |
379 | 0 | mmap_file->mapping_size = mmap_file->file_size * 2; |
380 | |
|
381 | 0 | #if defined(__linux__) |
382 | 0 | int64_t old_mapping_size = mmap_file->mapping_size; |
383 | | |
384 | | /* mremap is the best option as it also ensures that the old data is still available in c mode. Unfortunately, it |
385 | | is no POSIX standard and only available on Linux */ |
386 | 0 | char* new_address = mremap(mmap_file->addr, old_mapping_size, mmap_file->mapping_size, MREMAP_MAYMOVE); |
387 | | #else |
388 | | if (mmap_file->is_memory_only) { |
389 | | BLOSC_TRACE_ERROR("Remapping a memory-mapping in c mode is only possible on Linux." |
390 | | "Please specify either a different mode or set initial_mapping_size to a large enough number."); |
391 | | return 0; |
392 | | } |
393 | | /* Extend the current mapping with the help of MAP_FIXED */ |
394 | | int64_t offset = 0; |
395 | | char* new_address = mmap( |
396 | | mmap_file->addr, |
397 | | mmap_file->mapping_size, |
398 | | mmap_file->access_flags, |
399 | | mmap_file->map_flags | MAP_FIXED, |
400 | | mmap_file->fd, |
401 | | offset |
402 | | ); |
403 | | #endif |
404 | |
|
405 | 0 | if (new_address == MAP_FAILED) { |
406 | 0 | BLOSC_TRACE_ERROR("Cannot remap the memory-mapped file (error: %s).", strerror(errno)); |
407 | 0 | if (munmap(mmap_file->addr, mmap_file->mapping_size) < 0) { |
408 | 0 | BLOSC_TRACE_ERROR("Cannot unmap the memory-mapped file (error: %s).", strerror(errno)); |
409 | 0 | } |
410 | | |
411 | 0 | return 0; |
412 | 0 | } |
413 | | |
414 | 0 | mmap_file->addr = new_address; |
415 | 0 | } |
416 | 0 | #endif |
417 | | |
418 | 0 | memcpy(mmap_file->addr + position, ptr, n_bytes); |
419 | 0 | return nitems; |
420 | 0 | } |
421 | | |
422 | 0 | int64_t blosc2_stdio_mmap_read(void **ptr, int64_t size, int64_t nitems, int64_t position, void *stream) { |
423 | 0 | blosc2_stdio_mmap *mmap_file = (blosc2_stdio_mmap *) stream; |
424 | |
|
425 | 0 | if (position < 0) { |
426 | 0 | BLOSC_TRACE_ERROR("Cannot read from a negative position."); |
427 | 0 | *ptr = NULL; |
428 | 0 | return 0; |
429 | 0 | } |
430 | | |
431 | 0 | if (position + size * nitems > mmap_file->file_size) { |
432 | 0 | BLOSC_TRACE_ERROR("Cannot read beyond the end of the memory-mapped file."); |
433 | 0 | *ptr = NULL; |
434 | 0 | return 0; |
435 | 0 | } |
436 | | |
437 | 0 | *ptr = mmap_file->addr + position; |
438 | |
|
439 | 0 | return nitems; |
440 | 0 | } |
441 | | |
442 | 0 | int blosc2_stdio_mmap_truncate(void *stream, int64_t size) { |
443 | 0 | blosc2_stdio_mmap *mmap_file = (blosc2_stdio_mmap *) stream; |
444 | |
|
445 | 0 | if (mmap_file->file_size == size) { |
446 | 0 | return 0; |
447 | 0 | } |
448 | | |
449 | 0 | mmap_file->file_size = size; |
450 | | |
451 | | /* No file operations in c mode */ |
452 | 0 | if (mmap_file->is_memory_only) { |
453 | 0 | return 0; |
454 | 0 | } |
455 | | |
456 | | #if defined(_WIN32) |
457 | | /* On Windows, we can truncate the file only at the end after we released the mapping */ |
458 | | return 0; |
459 | | #else |
460 | 0 | return ftruncate(mmap_file->fd, size); |
461 | 0 | #endif |
462 | 0 | } |
463 | | |
464 | 0 | int blosc2_stdio_mmap_destroy(void* params) { |
465 | 0 | blosc2_stdio_mmap *mmap_file = (blosc2_stdio_mmap *) params; |
466 | 0 | int err = 0; |
467 | |
|
468 | | #if defined(_WIN32) |
469 | | if (mmap_file->access_flags == PAGE_READWRITE) { |
470 | | /* Ensure modified pages are written to disk */ |
471 | | if (!FlushViewOfFile(mmap_file->addr, mmap_file->file_size)) { |
472 | | _print_last_error(); |
473 | | BLOSC_TRACE_ERROR("Cannot flush the memory-mapped view to disk."); |
474 | | err = -1; |
475 | | } |
476 | | HANDLE file_handle = (HANDLE) _get_osfhandle(mmap_file->fd); |
477 | | if (!FlushFileBuffers(file_handle)) { |
478 | | _print_last_error(); |
479 | | BLOSC_TRACE_ERROR("Cannot flush the memory-mapped file to disk."); |
480 | | err = -1; |
481 | | } |
482 | | } |
483 | | |
484 | | if (!UnmapViewOfFile(mmap_file->addr)) { |
485 | | _print_last_error(); |
486 | | BLOSC_TRACE_ERROR("Cannot unmap the memory-mapped file."); |
487 | | err = -1; |
488 | | } |
489 | | if (!CloseHandle(mmap_file->mmap_handle)) { |
490 | | _print_last_error(); |
491 | | BLOSC_TRACE_ERROR("Cannot close the handle to the memory-mapped file."); |
492 | | err = -1; |
493 | | } |
494 | | int rc = _chsize_s(mmap_file->fd, mmap_file->file_size); |
495 | | if (rc != 0) { |
496 | | BLOSC_TRACE_ERROR( |
497 | | "Cannot extend the file size to %" PRId64 " bytes (error: %s).", mmap_file->file_size, strerror(errno)); |
498 | | err = -1; |
499 | | } |
500 | | #else |
501 | 0 | if ((mmap_file->access_flags & PROT_WRITE) && !mmap_file->is_memory_only) { |
502 | | /* Ensure modified pages are written to disk */ |
503 | | /* This is important since not every munmap implementation flushes modified pages to disk |
504 | | (e.g.: https://nfs.sourceforge.net/#faq_d8) */ |
505 | 0 | int rc = msync(mmap_file->addr, mmap_file->file_size, MS_SYNC); |
506 | 0 | if (rc < 0) { |
507 | 0 | BLOSC_TRACE_ERROR("Cannot sync the memory-mapped file to disk (error: %s).", strerror(errno)); |
508 | 0 | err = -1; |
509 | 0 | } |
510 | 0 | } |
511 | | |
512 | 0 | if (munmap(mmap_file->addr, mmap_file->mapping_size) < 0) { |
513 | 0 | BLOSC_TRACE_ERROR("Cannot unmap the memory-mapped file (error: %s).", strerror(errno)); |
514 | 0 | err = -1; |
515 | 0 | } |
516 | 0 | #endif |
517 | | /* Also closes the HANDLE on Windows */ |
518 | 0 | if (fclose(mmap_file->file) < 0) { |
519 | 0 | BLOSC_TRACE_ERROR("Could not close the memory-mapped file."); |
520 | 0 | err = -1; |
521 | 0 | } |
522 | | |
523 | 0 | free(mmap_file->urlpath); |
524 | 0 | if (mmap_file->needs_free) { |
525 | 0 | free(mmap_file); |
526 | 0 | } |
527 | |
|
528 | 0 | return err; |
529 | 0 | } |