Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions include/chunkio/cio_file.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ struct cio_file {
size_t realloc_size; /* chunk size to increase alloc */
char *path; /* root path + stream */
char *map; /* map of data */
struct cio_ctx *ctx; /* owning context */
#ifdef _WIN32
HANDLE backing_file;
HANDLE backing_mapping;
Expand All @@ -49,6 +50,8 @@ struct cio_file {
char *st_content;
crc_t crc_cur; /* crc: current value calculated */
int crc_reset; /* crc: must recalculate from the beginning ? */
int auto_remap_warned; /* has sync auto-remap warning been emitted? */
int map_truncated_warned; /* has RO truncation warning been emitted? */
};

size_t cio_file_real_size(struct cio_file *cf);
Expand Down
48 changes: 43 additions & 5 deletions src/cio_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,10 @@ static int munmap_file(struct cio_ctx *ctx, struct cio_chunk *ch)
}

/* Unmap file */
cio_file_native_unmap(cf);
ret = cio_file_native_unmap(cf);
if (ret != CIO_OK) {
return -1;
}

cf->data_size = 0;
cf->alloc_size = 0;
Expand All @@ -343,6 +346,7 @@ static int mmap_file(struct cio_ctx *ctx, struct cio_chunk *ch, size_t size)
{
ssize_t content_size;
size_t fs_size;
size_t requested_map_size;
int ret;
struct cio_file *cf;

Expand Down Expand Up @@ -413,6 +417,7 @@ static int mmap_file(struct cio_ctx *ctx, struct cio_chunk *ch, size_t size)
cf->alloc_size = size;

/* Map the file */
requested_map_size = cf->alloc_size;
ret = cio_file_native_map(cf, cf->alloc_size);

if (ret != CIO_OK) {
Expand All @@ -421,6 +426,21 @@ static int mmap_file(struct cio_ctx *ctx, struct cio_chunk *ch, size_t size)
return CIO_ERROR;
}

if ((cf->flags & CIO_OPEN_RD) && requested_map_size != cf->alloc_size) {
if (cf->map_truncated_warned == CIO_FALSE) {
cio_log_warn(ctx,
"[cio file] truncated read-only map from %zu to %zu bytes: %s/%s",
requested_map_size,
cf->alloc_size,
ch->st->name,
ch->name);
cf->map_truncated_warned = CIO_TRUE;
}
}
else {
cf->map_truncated_warned = CIO_FALSE;
}

/* check content data size */
if (fs_size > 0) {
content_size = cio_file_st_get_content_len(cf->map,
Expand Down Expand Up @@ -664,6 +684,9 @@ struct cio_file *cio_file_open(struct cio_ctx *ctx,
cf->crc_cur = cio_crc32_init();
cf->path = path;
cf->map = NULL;
cf->ctx = ctx;
cf->auto_remap_warned = CIO_FALSE;
cf->map_truncated_warned = CIO_FALSE;
ch->backend = cf;

#ifdef _WIN32
Expand Down Expand Up @@ -801,9 +824,9 @@ static int _cio_file_up(struct cio_chunk *ch, int enforced)
return CIO_ERROR;
}

if (cf->fd > 0) {
if (cio_file_native_is_open(cf)) {
cio_log_error(ch->ctx, "[cio file] file descriptor already exists: "
"[fd=%i] %s:%s", cf->fd, ch->st->name, ch->name);
"%s:%s", ch->st->name, ch->name);
return CIO_ERROR;
}

Expand Down Expand Up @@ -908,7 +931,11 @@ int cio_file_down(struct cio_chunk *ch)
}

/* unmap memory */
munmap_file(ch->ctx, ch);
ret = munmap_file(ch->ctx, ch);

if (ret != 0) {
return -1;
}

/* Allocated map size is zero */
cf->alloc_size = 0;
Expand All @@ -921,7 +948,12 @@ int cio_file_down(struct cio_chunk *ch)
}

/* Close file descriptor */
cio_file_native_close(cf);
ret = cio_file_native_close(cf);

if (ret != CIO_OK) {
cio_errno();
return -1;
}

return 0;
}
Expand Down Expand Up @@ -1135,6 +1167,12 @@ int cio_file_sync(struct cio_chunk *ch)
return 0;
}

/* If chunk is down (unmapped), there's nothing to sync */
/* You can only write to a chunk when it's up, so if it's down, no pending changes exist */
if (!cio_file_native_is_mapped(cf)) {
return 0;
}

if (cf->synced == CIO_TRUE) {
return 0;
}
Expand Down
1 change: 1 addition & 0 deletions src/cio_file_unix.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ int cio_file_native_unmap(struct cio_file *cf)

cf->alloc_size = 0;
cf->map = NULL;
cf->map_truncated_warned = CIO_FALSE;

return CIO_OK;
}
Expand Down
93 changes: 85 additions & 8 deletions src/cio_file_win32.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,14 @@ int cio_file_native_unmap(struct cio_file *cf)
return CIO_ERROR;
}

if (!cio_file_native_is_open(cf)) {
return CIO_OK;
}

/* Check if already unmapped first */
if (!cio_file_native_is_mapped(cf)) {
return CIO_OK;
}

/* On Windows, we can unmap even if file handle is closed */
/* The mapping handle maintains the reference */

result = UnmapViewOfFile(cf->map);

if (result == 0) {
Expand All @@ -54,11 +54,18 @@ int cio_file_native_unmap(struct cio_file *cf)
return CIO_ERROR;
}

CloseHandle(cf->backing_mapping);
result = CloseHandle(cf->backing_mapping);

if (result == 0) {
cio_file_native_report_os_error();

return CIO_ERROR;
}

cf->backing_mapping = INVALID_HANDLE_VALUE;
cf->alloc_size = 0;
cf->map = NULL;
cf->map_truncated_warned = CIO_FALSE;

return CIO_OK;
}
Expand All @@ -67,6 +74,9 @@ int cio_file_native_map(struct cio_file *cf, size_t map_size)
{
DWORD desired_protection;
DWORD desired_access;
size_t file_size;
size_t actual_map_size;
int ret;

if (cf == NULL) {
return CIO_ERROR;
Expand All @@ -92,17 +102,48 @@ int cio_file_native_map(struct cio_file *cf, size_t map_size)
return CIO_ERROR;
}

/* Get current file size to ensure we don't map beyond it for read-only files */
ret = cio_file_native_get_size(cf, &file_size);
if (ret != CIO_OK) {
return CIO_ERROR;
}

/* For read-only files, we cannot map beyond the file size */
/* For read-write files, if map_size > file_size, we should resize first */
if (cf->flags & CIO_OPEN_RD) {
if (map_size > file_size) {
actual_map_size = file_size;
}
else {
actual_map_size = map_size;
}
}
else {
/* For RW files, if map_size > file_size, resize the file first */
if (map_size > file_size) {
ret = cio_file_native_resize(cf, map_size);
if (ret != CIO_OK) {
return CIO_ERROR;
}
}
actual_map_size = map_size;
}

/* CreateFileMappingA requires size as two DWORDs (high and low) */
/* Use actual_map_size to ensure consistency */
cf->backing_mapping = CreateFileMappingA(cf->backing_file, NULL,
desired_protection,
0, 0, NULL);
(DWORD)(actual_map_size >> 32),
(DWORD)(actual_map_size & 0xFFFFFFFFUL),
NULL);

if (cf->backing_mapping == NULL) {
cio_file_native_report_os_error();

return CIO_ERROR;
}

cf->map = MapViewOfFile(cf->backing_mapping, desired_access, 0, 0, map_size);
cf->map = MapViewOfFile(cf->backing_mapping, desired_access, 0, 0, actual_map_size);

if (cf->map == NULL) {
cio_file_native_report_os_error();
Expand All @@ -114,7 +155,7 @@ int cio_file_native_map(struct cio_file *cf, size_t map_size)
return CIO_ERROR;
}

cf->alloc_size = map_size;
cf->alloc_size = actual_map_size;

return CIO_OK;
}
Expand Down Expand Up @@ -474,6 +515,38 @@ int cio_file_native_delete(struct cio_file *cf)
{
int result;

if (cf == NULL) {
return CIO_ERROR;
}

if (cio_file_native_is_mapped(cf)) {
if (cf->ctx != NULL) {
cio_log_warn(cf->ctx,
"[cio file] auto-unmapping chunk prior to delete: %s",
cf->path);
}

result = cio_file_native_unmap(cf);

if (result != CIO_OK) {
return result;
}
}

if (cio_file_native_is_open(cf)) {
if (cf->ctx != NULL) {
cio_log_warn(cf->ctx,
"[cio file] closing handle prior to delete: %s",
cf->path);
}

result = cio_file_native_close(cf);

if (result != CIO_OK) {
return result;
}
}

result = DeleteFileA(cf->path);

if (result == 0) {
Expand All @@ -489,6 +562,10 @@ int cio_file_native_sync(struct cio_file *cf, int sync_mode)
{
int result;

if (!cio_file_native_is_mapped(cf)) {
return CIO_ERROR;
}

result = FlushViewOfFile(cf->map, cf->alloc_size);

if (result == 0) {
Expand Down
8 changes: 8 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ if(CIO_BACKEND_FILESYSTEM)
)
endif()

# Windows-specific inconsistency tests
if(WIN32 AND CIO_BACKEND_FILESYSTEM)
set(UNIT_TESTS_FILES
${UNIT_TESTS_FILES}
fs_windows.c
)
endif()

set(CIO_TESTS_DATA_PATH ${CMAKE_CURRENT_SOURCE_DIR}/)
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/cio_tests_internal.h.in"
Expand Down
Loading