file_win32 implementation, unit tests and int tests

This commit is contained in:
Parth Aggarwal 2020-07-17 16:55:23 -04:00
Родитель 47ba81ccad
Коммит 63a9d497a2
7 изменённых файлов: 542 добавлений и 78 удалений

Просмотреть файл

@ -38,7 +38,7 @@ MOCKABLE_FUNCTION(, FILE_HANDLE, file_create, EXECUTION_ENGINE_HANDLE, execution
MOCKABLE_FUNCTION(, void, file_destroy, FILE_HANDLE, handle);
MOCKABLE_FUNCTION_WITH_RETURNS(, FILE_WRITE_ASYNC_RESULT, file_write_async, FILE_HANDLE, handle, const unsigned char*, source, uint32_t, size, uint64_t, position, FILE_WRITE_CB, user_callback, void*, user_context)(FILE_WRITE_ASYNC_OK, FILE_WRITE_ASYNC_ERROR);
MOCKABLE_FUNCTION_WITH_RETURNS(, FILE_READ_ASYNC_RESULT, file_read_async, FILE_HANDLE, handle, uint64_t, position, unsigned char*, destination, uint32_t, size,FILE_READ_CB, user_callback, void*, user_context)(FILE_READ_ASYNC_OK, FILE_READ_ASYNC_ERROR);
MOCKABLE_FUNCTION_WITH_RETURNS(, FILE_READ_ASYNC_RESULT, file_read_async, FILE_HANDLE, handle, unsigned char*, destination, uint64_t, position, uint32_t, size, FILE_CB, user_callback, void*, user_context)(FILE_READ_ASYNC_OK, FILE_READ_ASYNC_ERROR);
MOCKABLE_FUNCTION_WITH_RETURNS(, int, file_extend, FILE_HANDLE, handle, uint64_t, desired_size)(0, MU_FAILURE);
```
@ -49,7 +49,7 @@ MOCKABLE_FUNCTION_WITH_RETURNS(, int, file_extend, FILE_HANDLE, handle, uint64_t
MOCKABLE_FUNCTION(, FILE_HANDLE, file_create,FILE_REPORT_FAULT, user_report_fault_callback, void*, user_report_fault_context, EXECUTION_ENGINE_HANDLE, execution_engine, const char*, full_file_name);
```
If a file by the name `full_file_name` does not exist, `file_create` creates a file by that name, opens it and returns its handle. If the file does exist, `file_create` opens the file and returns its handle.
If a file by the name `full_file_name` does not exist, `file_create` creates a file by that name, opens it and returns its handle. If the file does exist, `file_create` opens the file and returns its handle. `file_create` shall register `user_report_fault_callback` with argument `user_report_fault_context` as the callback function to be called when the callback specified by the user for a specific asynchronous operation cannot be called.
**SRS_FILE_43_033: [** If `execution_engine` is `NULL`, `file_create` shall fail and return `NULL`. **]**
@ -61,8 +61,6 @@ If a file by the name `full_file_name` does not exist, `file_create` creates a f
**SRS_FILE_43_001: [** `file_create` shall open the file named `full_file_name` for asynchronous operations and return its handle. **]**
**SRS_FILE_43_038: [** `file_create` shall register `user_report_fault_callback` with argument `user_report_fault_context` as the callback function to be called when the callback specified by the user for a specific asynchronous operation cannot be called. **]**
**SRS_FILE_43_034: [** If there are any failures, `file_create` shall fail and return `NULL`. **]**
## file_destroy
@ -91,9 +89,11 @@ MOCKABLE_FUNCTION_WITH_RETURNS(, FILE_WRITE_ASYNC_RESULT, file_write_async, FILE
**SRS_FILE_43_010: [** If `source` is `NULL` then `file_write_async` shall fail and return `FILE_WRITE_ASYNC_INVALID_ARGS`. **]**
**SRS_FILE_43_012: [** If `user_callback` is `NULL` then `file_write_async` shall fail and return `FILE_WRITE_ASYNC_INVALID_ARGS`. **]**
**SRS_FILE_43_040: [** If `position` + `size` is greater than `INT64_MAX`, then `file_write_async` shall fail and return `FILE_WRITE_ASYNC_INVALID_ARGS`. **]**
**SRS_FILE_43_012: [** If `user_callback` is `NULL` then `file_write_async` shall fail and return `FILE_WRITE_ASYNC_INVALID_ARGS`. **]**
**SRS_FILE_43_042: [** If `size` is 0 then `file_write_async` shall fail and return `FILE_WRITE_ASYNC_INVALID_ARGS`. **]**
**SRS_FILE_43_014: [** `file_write_async` shall enqueue a write request to write `source`'s content to the `position` offset in the file. **]**
@ -121,6 +121,8 @@ MOCKABLE_FUNCTION_WITH_RETURNS(, FILE_READ_ASYNC_RESULT, file_read_async, FILE_H
**SRS_FILE_43_020: [** If `user_callback` is `NULL` then `file_read_async` shall fail and return `FILE_READ_ASYNC_INVALID_ARGS`. **]**
**SRS_FILE_43_043: [** If `size` is 0 then `file_read_async` shall fail and return `FILE_READ_ASYNC_INVALID_ARGS`. **]**
**SRS_FILE_43_021: [** `file_read_async` shall enqueue a read request to read `handle`'s content at `position` offset and write it to `destination`. **]**
**SRS_FILE_43_036: [** If the call to read the file fails, `file_read_async` shall fail and return `FILE_READ_ASYNC_READ_ERROR`. **]**

Просмотреть файл

@ -35,14 +35,13 @@ MU_DEFINE_ENUM(FILE_READ_ASYNC_RESULT, FILE_READ_ASYNC_VALUES);
typedef struct FILE_HANDLE_DATA_TAG* FILE_HANDLE;
typedef void(*FILE_REPORT_FAULT)(void* user_report_fault_context, const char* information);
typedef void(*FILE_WRITE_CB)(void* user_context, bool is_successful);
typedef void(*FILE_READ_CB)(void* user_context, bool is_successful);
typedef void(*FILE_CB)(void* user_context, bool is_successful);
MOCKABLE_FUNCTION(, FILE_HANDLE, file_create, EXECUTION_ENGINE_HANDLE, execution_engine, const char*, full_file_name, FILE_REPORT_FAULT, user_report_fault_callback, void*, user_report_fault_context);
MOCKABLE_FUNCTION(, void, file_destroy, FILE_HANDLE, handle);
MOCKABLE_FUNCTION_WITH_RETURNS(, FILE_WRITE_ASYNC_RESULT, file_write_async, FILE_HANDLE, handle, const unsigned char*, source, uint32_t, size, uint64_t, position, FILE_WRITE_CB, user_callback, void*, user_context)(FILE_WRITE_ASYNC_OK, FILE_WRITE_ASYNC_ERROR);
MOCKABLE_FUNCTION_WITH_RETURNS(, FILE_READ_ASYNC_RESULT, file_read_async, FILE_HANDLE, handle, uint64_t, position, unsigned char*, destination, uint32_t, size,FILE_READ_CB, user_callback, void*, user_context)(FILE_READ_ASYNC_OK, FILE_READ_ASYNC_ERROR);
MOCKABLE_FUNCTION_WITH_RETURNS(, FILE_WRITE_ASYNC_RESULT, file_write_async, FILE_HANDLE, handle, const unsigned char*, source, uint32_t, size, uint64_t, position, FILE_CB, user_callback, void*, user_context)(FILE_WRITE_ASYNC_OK, FILE_WRITE_ASYNC_ERROR);
MOCKABLE_FUNCTION_WITH_RETURNS(, FILE_READ_ASYNC_RESULT, file_read_async, FILE_HANDLE, handle, unsigned char*, destination, uint32_t, size, uint64_t, position, FILE_CB, user_callback, void*, user_context)(FILE_READ_ASYNC_OK, FILE_READ_ASYNC_ERROR);
MOCKABLE_FUNCTION_WITH_RETURNS(, int, file_extend, FILE_HANDLE, handle, uint64_t, desired_size)(0, MU_FAILURE);
#ifdef __cplusplus

Просмотреть файл

@ -8,6 +8,7 @@ endif()
if(${run_int_tests})
add_subdirectory(interlocked_int)
add_subdirectory(file_int)
if(MSVC)
# waiting for timer to be implemented on linux
add_subdirectory(sync_int)

Просмотреть файл

@ -31,14 +31,13 @@ MU_DEFINE_ENUM(FILE_READ_ASYNC_RESULT, FILE_READ_ASYNC_VALUES);
typedef struct FILE_HANDLE_DATA_TAG* FILE_HANDLE;
typedef void(*FILE_REPORT_FAULT)(void* user_report_fault_context, const char* information);
typedef void(*FILE_WRITE_CB)(void* user_context, bool is_successful);
typedef void(*FILE_READ_CB)(void* user_context, bool is_successful);
typedef void(*FILE_CB)(void* user_context, bool is_successful);
MOCKABLE_FUNCTION(, FILE_HANDLE, file_create, EXECUTION_ENGINE_HANDLE, execution_engine, const char*, full_file_name, FILE_REPORT_FAULT, user_report_fault_callback, void*, user_report_fault_context);
MOCKABLE_FUNCTION(, void, file_destroy, FILE_HANDLE, handle);
MOCKABLE_FUNCTION_WITH_RETURNS(, FILE_WRITE_ASYNC_RESULT, file_write_async, FILE_HANDLE, handle, const unsigned char*, source, uint32_t, size, uint64_t, position, FILE_WRITE_CB, user_callback, void*, user_context)(FILE_WRITE_ASYNC_OK, FILE_WRITE_ASYNC_ERROR);
MOCKABLE_FUNCTION_WITH_RETURNS(, FILE_READ_ASYNC_RESULT, file_read_async, FILE_HANDLE, handle, uint64_t, position, unsigned char*, destination, uint32_t, size,FILE_READ_CB, user_callback, void*, user_context)(FILE_READ_ASYNC_OK, FILE_READ_ASYNC_ERROR);
MOCKABLE_FUNCTION_WITH_RETURNS(, FILE_READ_ASYNC_RESULT, file_read_async, FILE_HANDLE, handle, unsigned char*, destination, uint32_t, size, uint64_t, position, FILE_CB, user_callback, void*, user_context)(FILE_READ_ASYNC_OK, FILE_READ_ASYNC_ERROR);
MOCKABLE_FUNCTION_WITH_RETURNS(, int, file_extend, FILE_HANDLE, handle, uint64_t, desired_size)(0, MU_FAILURE);
```
@ -53,6 +52,8 @@ MOCKABLE_FUNCTION(, FILE_HANDLE, file_create, EXECUTION_ENGINE_HANDLE, execution
**SRS_FILE_LINUX_43_038: [** If `full_file_name` is `NULL` then `file_create` shall fail and return `NULL`. **]**
**SRS_FILE_LINUX_43_050: [** If full_file_name is an empty string, `file_create` shall fail and return `NULL`. **]**
**SRS_FILE_LINUX_43_029: [** `file_create` shall allocate a `FILE_HANDLE`. **]**
**SRS_FILE_LINUX_43_001: [** `file_create` shall call `open` with `full_file_name` as `pathname` and flags `O_CREAT`, `O_RDWR`, `O_DIRECT` and `O_LARGEFILE`. **]**
@ -82,10 +83,12 @@ MOCKABLE_FUNCTION_WITH_RETURNS(, FILE_WRITE_ASYNC_RESULT, file_write_async, FILE
**SRS_FILE_LINUX_43_032: [** If `source` is `NULL` then `file_write_async` shall fail and return `FILE_WRITE_ASYNC_INVALID_ARGS`. **]**
**SRS_FILE_LINUX_43_048: [** If `size` is 0 then `file_write_async` shall fail and return `FILE_WRITE_ASYNC_INVALID_ARGS`. **]**
**SRS_FILE_LINUX_43_051: [** If `position` + `size` is greater than `INT64_MAX`, then `file_write_async` shall fail and return `FILE_WRITE_ASYNC_INVALID_ARGS`. **]**
**SRS_FILE_LINUX_43_049: [** **SRS_FILE_LINUX_43_033: [** If `user_callback` is `NULL` then `file_write_async` shall fail and return `FILE_WRITE_ASYNC_INVALID_ARGS`. **]** **]**
**SRS_FILE_LINUX_43_048: [** If `size` is 0 then `file_write_async` shall fail and return `FILE_WRITE_ASYNC_INVALID_ARGS`. **]**
**SRS_FILE_LINUX_43_019: [** `file_write_async` shall allocate a struct to hold `handle`, `source`, `size`, `user_callback` and `user_context`. **]**
**SRS_FILE_LINUX_43_004: [** `file_write_async` shall allocate a `sigevent` struct with `SIGEV_THREAD` as `sigev_notify`, the allocated struct as `sigev_value`, `on_file_write_complete_linux` as `sigev_notify_function`, `NULL` as `sigev_notify_attributes`. **]**
@ -103,7 +106,7 @@ MOCKABLE_FUNCTION_WITH_RETURNS(, FILE_WRITE_ASYNC_RESULT, file_write_async, FILE
## file_read_async
```c
MOCKABLE_FUNCTION_WITH_RETURNS(, FILE_READ_ASYNC_RESULT, file_read_async, FILE_HANDLE, handle, uint64_t, position, unsigned char*, destination, uint32_t, size,FILE_READ_CB, user_callback, void*, user_context)(FILE_READ_ASYNC_OK, FILE_READ_ASYNC_ERROR);
MOCKABLE_FUNCTION_WITH_RETURNS(, FILE_READ_ASYNC_RESULT, file_read_async, FILE_HANDLE, handle, unsigned char*, destination, uint32_t, size, uint64_t, position, FILE_CB, user_callback, void*, user_context)(FILE_READ_ASYNC_OK, FILE_READ_ASYNC_ERROR);
```
**SRS_FILE_LINUX_43_034: [** If `handle` is `NULL` then `file_read_async` shall fail and return `FILE_READ_ASYNC_INVALID_ARGS`. **]**
@ -112,6 +115,8 @@ MOCKABLE_FUNCTION_WITH_RETURNS(, FILE_READ_ASYNC_RESULT, file_read_async, FILE_H
**SRS_FILE_LINUX_43_035: [** If `user_callback` is `NULL` then `file_read_async` shall fail and return `FILE_READ_ASYNC_INVALID_ARGS`. **]**
**SRS_FILE_LINUX_43_052: [** If `size` is 0 then `file_read_async` shall fail and return `FILE_READ_ASYNC_INVALID_ARGS`. **]**
**SRS_FILE_LINUX_43_045: [** `file_read_async` shall allocate a struct to hold `handle`, `destination`, `user_callback` and `user_context`. **]**
**SRS_FILE_LINUX_43_008: [** `file_read_async` shall allocate a `sigevent` struct with `SIGEV_THREAD` as `sigev_notify`, `user_context` as `sigev_value`, `on_file_read_complete_linux` as `sigev_notify_function`, `NULL` as `sigev_notify_attributes`. **]**
@ -142,7 +147,7 @@ Will be implemented later.
static void on_file_write_complete_linux( FILE_LINUX_WRITE* write_info);
```
`on_file_write_complete_linux` is called when an asynchronous write operation completes.
`on_file_write_complete_linux` is called when an asynchronous write operation completes. `on_file_write_complete_linux` calls the user-specified callback with the user-specified context and a bool indicating the success or failure of the asynchronous operation.
**SRS_FILE_LINUX_43_047: [** If `write_info` is `NULL`, `on_file_write_complete_linux` shall call `user_report_fault_callback` with `user_report_fault_context`. **]**
@ -160,7 +165,7 @@ static void on_file_write_complete_linux( FILE_LINUX_WRITE* write_info);
static void on_file_read_complete_linux( FILE_LINUX_READ* read_info);
```
`on_file_read_complete_linux` is called when an asynchronous read operation completes.
`on_file_read_complete_linux` is called when an asynchronous read operation completes. `on_file_write_complete_linux` calls the user-specified callback with the user-specified context and a bool indicating the success or failure of the asynchronous operation.
**SRS_FILE_LINUX_43_046: [** If `read_info` is `NULL`, `on_file_write_complete_linux` shall call `user_report_fault_callback` with `user_report_fault_context`. **]**

Просмотреть файл

@ -25,14 +25,13 @@ MU_DEFINE_ENUM(FILE_READ_ASYNC_RESULT, FILE_READ_ASYNC_VALUES);
typedef struct FILE_HANDLE_DATA_TAG* FILE_HANDLE;
typedef void(*FILE_REPORT_FAULT)(void* user_report_fault_context, const char* information);
typedef void(*FILE_WRITE_CB)(void* user_context, bool is_successful);
typedef void(*FILE_READ_CB)(void* user_context, bool is_successful);
typedef void(*FILE_CB)(void* user_context, bool is_successful);
MOCKABLE_FUNCTION(, FILE_HANDLE, file_create, EXECUTION_ENGINE_HANDLE, execution_engine, const char*, full_file_name, FILE_REPORT_FAULT, user_report_fault_callback, void*, user_report_fault_context);
MOCKABLE_FUNCTION(, void, file_destroy, FILE_HANDLE, handle);
MOCKABLE_FUNCTION_WITH_RETURNS(, FILE_WRITE_ASYNC_RESULT, file_write_async, FILE_HANDLE, handle, const unsigned char*, source, uint32_t, size, uint64_t, position, FILE_WRITE_CB, user_callback, void*, user_context)(FILE_WRITE_ASYNC_OK, FILE_WRITE_ASYNC_ERROR);
MOCKABLE_FUNCTION_WITH_RETURNS(, FILE_READ_ASYNC_RESULT, file_read_async, FILE_HANDLE, handle, uint64_t, position, unsigned char*, destination, uint32_t, size,FILE_READ_CB, user_callback, void*, user_context)(FILE_READ_ASYNC_OK, FILE_READ_ASYNC_ERROR);
MOCKABLE_FUNCTION_WITH_RETURNS(, FILE_READ_ASYNC_RESULT, file_read_async, FILE_HANDLE, handle, unsigned char*, destination, uint32_t, size, uint64_t, position, FILE_CB, user_callback, void*, user_context)(FILE_READ_ASYNC_OK, FILE_READ_ASYNC_ERROR);
MOCKABLE_FUNCTION_WITH_RETURNS(, int, file_extend, FILE_HANDLE, handle, uint64_t, desired_size)(0, MU_FAILURE);
```
@ -47,23 +46,25 @@ MOCKABLE_FUNCTION(, FILE_HANDLE, file_create, EXECUTION_ENGINE_HANDLE, execution
**SRS_FILE_WIN32_43_048: [** If `full_file_name` is `NULL` then `file_create` shall fail and return `NULL`. **]**
**SRS_FILE_WIN32_43_059: [** If full_file_name is an empty string, `file_create` shall fail and return `NULL`. **]**
**SRS_FILE_WIN32_43_041: [** `file_create` shall allocate a `FILE_HANDLE`. **]**
**SRS_FILE_WIN32_43_001: [** `file_create` shall call `CreateFileA` with `full_file_name` as `lpFileName`, `GENERIC_READ|GENERIC_WRITE` as `dwDesiredAccess`, `FILE_SHARED_READ` as `dwShareMode`, `NULL` as `lpSecurityAttributes`, `OPEN_ALWAYS` as `dwCreationDisposition`, `FILE_FLAG_OVERLAPPED|FILE_FLAG_WRITE_THROUGH` as `dwFlagsAndAttributes` and `NULL` as `hTemplateFile`. **]**
**SRS_FILE_WIN32_43_002: [** `file_create` shall call `SetFileCompletionNotificationModes` to disable calling the completion port when an async operations finishes synchrounously. **]**
**SRS_FILE_WIN32_43_002: [** `file_create` shall call `SetFileCompletionNotificationModes` to disable calling the completion port when an async operations finishes synchronously. **]**
**SRS_FILE_WIN32_43_003: [** `file_create` shall allocate a threadpool environment. **]**
**SRS_FILE_WIN32_43_003: [** `file_create` shall initialize a threadpool environment by calling `InitializeThreadpolEnvironment`. **]**
**SRS_FILE_WIN32_43_004: [** `file_create` shall obtain a `PTP_POOL` struct by calling `execution_engine_win32_get_threadpool` on `execution_engine`. **]**
**SRS_FILE_WIN32_43_005: [** `file_create` shall register the threadpool environment with `ptpPool` **]**
**SRS_FILE_WIN32_43_005: [** `file_create` shall register the threadpool environment by calling `SetThreadpoolCallbackPool` on the initialized threadpool environment and the obtained `ptp_pool` **]**
**SRS_FILE_WIN32_43_006: [** `file_create` shall create a cleanup group. **]**
**SRS_FILE_WIN32_43_006: [** `file_create` shall create a cleanup group by calling `CreateThreadpoolCleanupGroup`. **]**
**SRS_FILE_WIN32_43_007: [** `file_create` shall register the cleanup group with the threadpool environment. **]**
**SRS_FILE_WIN32_43_007: [** `file_create` shall register the cleanup group with the threadpool environment by calling `SetThreadpoolCallbackCleanupGroup`. **]**
**SRS_FILE_WIN32_43_033: [** `file_create` shall create a threadpool io with the allocated `FILE_HANDLE` and `on_file_io_complete_win32` as a callback. **]**
**SRS_FILE_WIN32_43_033: [** `file_create` shall create a threadpool io with the allocated `FILE_HANDLE` and `on_file_io_complete_win32` as a callback by calling `CreateThreadpoolIo` **]**
**SRS_FILE_WIN32_43_008: [** If there are any failures, `file_create` shall return `NULL`. **]**
@ -77,17 +78,17 @@ MOCKABLE_FUNCTION(, void, file_destroy, FILE_HANDLE, handle);
**SRS_FILE_WIN32_43_049: [** If `handle` is `NULL`, `file_destroy` shall return. **]**
**SRS_FILE_WIN32_43_011: [** `file_destroy` shall wait for all I/O to complete. **]**
**SRS_FILE_WIN32_43_011: [** `file_destroy` shall wait for all I/O to complete by calling `WaitForThreadpoolIoCallbacks`. **]**
**SRS_FILE_WIN32_43_012: [** `file_destroy` shall close the cleanup group. **]**
**SRS_FILE_WIN32_43_012: [** `file_destroy` shall close the cleanup group by calling `CloseThreadpoolCleanupGroup`. **]**
**SRS_FILE_WIN32_43_013: [** `file_destroy` shall destroy the environment. **]**
**SRS_FILE_WIN32_43_013: [** `file_destroy` shall destroy the environment by calling `DestroyThreadpoolEnvironment`. **]**
**SRS_FILE_WIN32_43_016: [** `file_destroy` shall call `CloseHandle` on `handle` **]**
**SRS_FILE_WIN32_43_016: [** `file_destroy` shall call `CloseHandle` on `handle->h_file` **]**
**SRS_FILE_WIN32_43_015: [** `file_destroy` shall close the threadpool IO. **]**
**SRS_FILE_WIN32_43_015: [** `file_destroy` shall close the threadpool IO by calling `CloseThreadPoolIo`. **]**
**SRS_FILE_WIN32_43_042: [** `file_destroy` shall free the `FILE_HANDLE`. **]**
**SRS_FILE_WIN32_43_042: [** `file_destroy` shall free the `handle`. **]**
## file_write_async
@ -102,13 +103,17 @@ MOCKABLE_FUNCTION_WITH_RETURNS(, FILE_WRITE_ASYNC_RESULT, file_write_async, FILE
**SRS_FILE_WIN32_43_045: [** If `user_callback` is `NULL` then `file_write_async` shall fail and return `FILE_WRITE_ASYNC_INVALID_ARGS`. **]**
**SRS_FILE_WIN32_43_060: [** If `position` + `size` is greater than `INT64_MAX`, then `file_write_async` shall fail and return `FILE_WRITE_ASYNC_INVALID_ARGS`. **]**
**SRS_FILE_WIN32_43_061: [** If `size` is 0 then `file_write_async` shall fail and return `FILE_WRITE_ASYNC_INVALID_ARGS`. **]**
**SRS_FILE_WIN32_43_017: [** `file_write_async` shall call `StartThreadpoolIo`. **]**
**SRS_FILE_WIN32_43_054: [** `file_write_async` shall create an event by calling `CreateEvent`. **]**
**SRS_FILE_WIN32_43_020: [** `file_write_async` shall allocate an `OVERLAPPED` struct and populate it with the created event and `position`. **]**
**SRS_FILE_WIN32_43_018: [** `file_write_async` shall allocate a context to store the allocated `OVERLAPPED` struct, `handle`, write as the type of asynchronous operation, `source`, `user_callback` and `user_context`. **]**
**SRS_FILE_WIN32_43_018: [** `file_write_async` shall allocate a context to store the allocated `OVERLAPPED` struct, `handle`, `size`, `user_callback` and `user_context`. **]**
**SRS_FILE_WIN32_43_021: [** `file_write_async` shall call `WriteFile` with `handle`, `source`, `size` and the allocated `OVERLAPPED` struct. **]**
@ -118,10 +123,12 @@ MOCKABLE_FUNCTION_WITH_RETURNS(, FILE_WRITE_ASYNC_RESULT, file_write_async, FILE
**SRS_FILE_WIN32_43_024: [** If `WriteFile` succeeds synchronously then `file_write_async` shall succeed, call `CancelThreadpoolIo`, call `user_callback` and return `FILE_WRITE_ASYNC_OK`. **]**
**SRS_FILE_WIN32_43_057: [** If there are any other failures, `file_write_async` shall fail and return `FILE_WRITE_ASYNC_ERROR`. **]**
## file_read_async
```c
MOCKABLE_FUNCTION_WITH_RETURNS(, FILE_READ_ASYNC_RESULT, file_read_async, FILE_HANDLE, handle, uint64_t, position, unsigned char*, destination, uint32_t, size,FILE_READ_CB, user_callback, void*, user_context)(FILE_READ_ASYNC_OK, FILE_READ_ASYNC_ERROR);
MOCKABLE_FUNCTION_WITH_RETURNS(, FILE_READ_ASYNC_RESULT, file_read_async, FILE_HANDLE, handle, unsigned char*, destination, uint32_t, size, uint64_t, position, FILE_CB, user_callback, void*, user_context)(FILE_READ_ASYNC_OK, FILE_READ_ASYNC_ERROR);
```
**SRS_FILE_WIN32_43_046: [** If `handle` is `NULL` then `file_read_async` shall fail and return `FILE_READ_ASYNC_INVALID_ARGS`. **]**
@ -130,22 +137,26 @@ MOCKABLE_FUNCTION_WITH_RETURNS(, FILE_READ_ASYNC_RESULT, file_read_async, FILE_H
**SRS_FILE_WIN32_43_047: [** If `user_callback` is `NULL` then `file_read_async` shall fail and return `FILE_READ_ASYNC_INVALID_ARGS`. **]**
**SRS_FILE_WIN32_43_062: [** If `size` is 0 then `file_read_async` shall fail and return `FILE_READ_ASYNC_INVALID_ARGS`. **]**
**SRS_FILE_WIN32_43_025: [** `file_read_async` shall call `StartThreadpoolIo`. **]**
**SRS_FILE_WIN32_43_055: [** `file_write_async` shall create an event by calling `CreateEvent`. **]**
**SRS_FILE_WIN32_43_055: [** `file_read_async` shall create an event by calling `CreateEvent`. **]**
**SRS_FILE_WIN32_43_028: [** `file_read_async` shall allocate an `OVERLAPPED` struct and populate it with the created event and `position`. **]**
**SRS_FILE_WIN32_43_026: [** `file_read_async` shall allocate a context to store the allocated `OVERLAPPED` struct, `destination`, `handle`, read as the type of asynchronous operation, `user_callback` and `user_context` **]**
**SRS_FILE_WIN32_43_026: [** `file_read_async` shall allocate a context to store the allocated `OVERLAPPED` struct, `destination`, `handle`, `size`, `user_callback` and `user_context` **]**
**SRS_FILE_WIN32_43_029: [** `file_read_async` shall call `ReadFile` with `handle`, `destination`, `size` and the allocated `OVERLAPPED` struct. **]**
**SRS_FILE_WIN32_43_030: [** If `ReadFile` fails synchronously and `GetLastError` indicates `ERROR_IO_PENDING` then `file_read_async` shall succeed and return `FILE_READ_ASYNC_OK`. **]**
**SRS_FILE_WIN32_43_031: [** If `ReadFile` fails synchronously and `GetLastError` does not indicate `ERROR_IO_PENDING` then `file_read_async` shall fail, call `CancelThreadpoolIo` and return `FILE_READ_ASYNC_WRITE_ERROR`. **]**
**SRS_FILE_WIN32_43_031: [** If `ReadFile` fails synchronously and `GetLastError` does not indicate `ERROR_IO_PENDING` then `file_read_async` shall fail, call `CancelThreadpoolIo` and return `FILE_READ_ASYNC_READ_ERROR`. **]**
**SRS_FILE_WIN32_43_032: [** If `ReadFile` succeeds synchronously then `file_read_async` shall succeed, call `CancelThreadpoolIo`, call `user_callback` and return `FILE_READ_ASYNC_OK`. **]**
**SRS_FILE_WIN32_43_058: [** If there are any other failures, `file_read_async` shall fail and return `FILE_READ_ASYNC_ERROR`. **]**
## file_extend
```c
@ -166,18 +177,14 @@ static void on_file_io_complete_win32(
PTP_IO io
);
```
`on_file_io_complete_win32` is called when a file operation completes asynchronously.
`on_file_io_complete_win32` is called when a file operation completes asynchronously. `on_file_io_complete_win32` calls the user-specified callback with the user-specified context and a bool indicating the success or failure of the asynchronous operation. If `on_file_io_complete_win32` is not able to recover the user-specified callback, it shall call the fault callback specified while creating the file.
**SRS_FILE_WIN32_43_057: [** If `overlapped` is `NULL`, `on_file_io_complete_win32` shall call `user_report_fault_callback` with `user_report_fault_context`. **]**
**SRS_FILE_WIN32_43_034: [** `on_file_io_complete_win32` shall recover the file handle, the number of bytes requested by the user, `user_callback` and `user_context` from the context containing `overlapped`. **]**
**SRS_FILE_WIN32_43_034: [** `on_file_io_complete_win32` shall recover the context containing `overlapped`. **]**
**SRS_FILE_WIN32_43_063: [** `on_file_io_complete_win32` shall call `GetOverlappedResult` to determine if the asynchronous operation was successful. **]**
**SRS_FILE_WIN32_43_053: [** `on_file_io_complete_win32` shall determine the type of asynchronous operation from the context. **]**
**SRS_FILE_WIN32_43_067: [** `on_file_io_complete_win32` shall compare `number_of_bytes_transferred` to the number of bytes requested by the user. **]**
**SRS_FILE_WIN32_43_056: [** If the type of asynchronous operation is neither read nor write, `on_file_io_complete_win32` shall call `user_report_fault_callback` with `user_report_fault_context`. **]**
**SRS_FILE_WIN32_43_066: [** `on_file_io_complete_win32` shall call `user_callback` with `is_successful` as `true` if and only if `GetOverlappedResult` returns `true` and `number_of_bytes_transferred` is equal to the number of bytes requested by the user. **]**
**SRS_FILE_WIN32_43_035: [** If `io_result` is not `NO_ERROR`, `on_file_io_complete_win32` shall call `user_callback` with `false` as `is_successful`. **]**
**SRS_FILE_WIN32_43_036: [** If the type of the asynchronous operation is read, `on_file_io_complete_win32` shall call `user_callback` with `user_context` and `true` as `is_successful`. **]**
**SRS_FILE_WIN32_43_039: [** If the type of the asynchronous operation is write, `on_file_io_complete_win32` shall call `user_callback` with `user_context` and `true` as `is_successful`. **]**
**SRS_FILE_WIN32_43_068: [** If either `GetOverlappedResult` returns `false` or `number_of_bytes_transferred` is not equal to the bytes requested by the user, `on_file_io_complete_win32` shall return `false`. **]**

Просмотреть файл

@ -1,32 +1,18 @@
// Copyright (C) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include <inttypes.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "windows.h"
#include "azure_c_logging/xlogging.h"
#include "execution_engine_win32.h"
#include "azure_c_pal/gballoc.h"
#include "azure_c_pal/file.h"
typedef struct FILE_WRITE_DATA_CONTEXT_TAG
{
FILE_WRITE_CB user_callback;
void* user_context;
const unsigned char* source;
uint32_t size;
}FILE_WRITE_DATA_CONTEXT;
typedef struct FILE_READ_DATA_CONTEXT_TAG
{
FILE_READ_CB user_callback;
void* user_context;
unsigned char* destination;
uint32_t size;
}FILE_READ_DATA_CONTEXT;
#define FILE_ASYNC_OPERATION_VALUES \
FILE_ASYNC_WRITE, \
FILE_ASYNC_READ
MU_DEFINE_ENUM(FILE_ASYNC_OPERATION, FILE_ASYNC_OPERATION_VALUES)
MU_DEFINE_ENUM_STRINGS(FILE_ASYNC_OPERATION, FILE_ASYNC_OPERATION_VALUES)
typedef struct FILE_HANDLE_DATA_TAG
{
PTP_POOL ptp_pool;
@ -39,18 +25,13 @@ typedef struct FILE_HANDLE_DATA_TAG
}FILE_HANDLE_DATA;
typedef union FILE_IO_DATA_TAG
{
FILE_READ_DATA_CONTEXT read_data;
FILE_WRITE_DATA_CONTEXT write_data;
}FILE_IO_DATA;
typedef struct FILE_WIN32_IO_TAG
{
OVERLAPPED ov;
FILE_HANDLE handle;
FILE_ASYNC_OPERATION type;
FILE_IO_DATA data;
FILE_CB user_callback;
void* user_context;
uint32_t size;
}FILE_WIN32_IO;
static void on_file_io_complete_win32(
@ -60,4 +41,472 @@ static void on_file_io_complete_win32(
ULONG io_result,
ULONG_PTR number_of_bytes_transferred,
PTP_IO io
);
);
static VOID NTAPI on_close_threadpool_group_member(
PVOID object_context, /*what was passed @ CreateThreadpoolIo*/
PVOID cleanup_context /*what was passed @ CloseThreadpoolCleanupGroupMembers*/
)
{
(void)object_context;
(void)cleanup_context;
}
IMPLEMENT_MOCKABLE_FUNCTION(
,
FILE_HANDLE, file_create,
EXECUTION_ENGINE_HANDLE, execution_engine,
const char*, full_file_name,
FILE_REPORT_FAULT, user_report_fault_callback,
void*, user_report_fault_context
)
{
FILE_HANDLE handle = (FILE_HANDLE)NULL;
bool result = true;
if
(
/*Codes_SRS_FILE_43_033: [ If execution_engine is NULL, file_create shall fail and return NULL. ]*/
/*Codes_SRS_FILE_WIN32_43_040: [ If execution_engine is NULL, file_create shall fail and return NULL. ]*/
(execution_engine == NULL) ||
/*Codes_SRS_FILE_43_002: [ If full_file_name is NULL then file_create shall fail and return NULL. ]*/
/*Codes_SRS_FILE_WIN32_43_048: [ If full_file_name is NULL then file_create shall fail and return NULL. ]*/
(full_file_name == NULL) ||
/*Codes_SRS_FILE_43_037: [ If full_file_name is an empty string, file_create shall fail and return NULL. ]*/
/*Codes_SRS_FILE_WIN32_43_059: [ If full_file_name is an empty string, file_create shall fail and return NULL. ]*/
(strlen(full_file_name) == 0)
)
{
LogError("Invalid arguments to file_create: EXECUTION_ENGINE_HANDLE execution_engine=%p, const char* full_file_name=%s, FILE_REPORT_FAULT user_report_callback=%p, void* user_report_faul_context=%p",
execution_engine, full_file_name, user_report_fault_callback, user_report_fault_context);
result = false;
}
else
{
/*Codes_SRS_FILE_WIN32_43_041: [ file_create shall allocate a FILE_HANDLE. ]*/
handle = malloc(sizeof(FILE_HANDLE_DATA));
if (handle == NULL) {
LogError("Failure in malloc");
result = false;
}
else
{
/*Codes_SRS_FILE_43_003: [ If a file with name full_file_name does not exist, file_create shall create a file with that name.]*/
/*Codes_SRS_FILE_43_001: [ file_create shall open the file named full_file_name for asynchronous operations and return its handle. ]*/
/*Codes_SRS_FILE_WIN32_43_001: [ file_create shall call CreateFileA with full_file_name as lpFileName, GENERIC_READ|GENERIC_WRITE as dwDesiredAccess, FILE_SHARED_READ as dwShareMode, NULL as lpSecurityAttributes, OPEN_ALWAYS as dwCreationDisposition, FILE_FLAG_OVERLAPPED|FILE_FLAG_WRITE_THROUGH as dwFlagsAndAttributes and NULL as hTemplateFile. ]*/
if ((handle->h_file = CreateFileA(
full_file_name, /*_In_ LPCTSTR lpFileName*/
GENERIC_READ | GENERIC_WRITE, /*_In_ DWORD dwDesiredAccess*/
FILE_SHARE_READ, /*_In_ DWORD dwShareMode*/
NULL, /*_In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes*/
OPEN_ALWAYS, /*_In_ DWORD dwCreationDisposition*/
FILE_FLAG_OVERLAPPED | FILE_FLAG_WRITE_THROUGH, /*_In_ DWORD dwFlagsAndAttributes*/
NULL /*_In_opt_ HANDLE hTemplateFile*/
)) == INVALID_HANDLE_VALUE)
{
LogError("Failure in CreateFileA, full_file_name=%s", full_file_name);
result = false;
}
else
{
/*Codes_SRS_FILE_WIN32_43_002: [ file_create shall call SetFileCompletionNotificationModes to disable calling the completion port when an async operations finishes synchrounously.]*/
if (!SetFileCompletionNotificationModes(handle->h_file, FILE_SKIP_COMPLETION_PORT_ON_SUCCESS))
{
LogError("Failure in SetFileCompletionNotificationModes, full_file_name=%s", full_file_name);
result = false;
}
else
{
/*Codes_SRS_FILE_WIN32_43_003: [ file_create shall initialize a threadpool environment by calling InitializeThreadpolEnvironment.]*/
InitializeThreadpoolEnvironment(&handle->cbe);
/*Codes_SRS_FILE_WIN32_43_004: [ file_create shall obtain a PTP_POOL struct by calling execution_engine_win32_get_threadpool on execution_engine.]*/
handle->ptp_pool = execution_engine_win32_get_threadpool(execution_engine);
/*Codes_SRS_FILE_WIN32_43_005: [ file_create shall register the threadpool environment by calling SetThreadpoolCallbackPool on the initialized threadpool environment and the obtained ptp_pool ]*/
SetThreadpoolCallbackPool(&handle->cbe, handle->ptp_pool);
/*Codes_SRS_FILE_WIN32_43_006: [ file_create shall create a cleanup group by calling CreateThreadpoolCleanupGroup.]*/
handle->ptp_cleanup_group = CreateThreadpoolCleanupGroup();
if (handle->ptp_cleanup_group == NULL)
{
LogError("Failure in CreateThreadpoolCleanupGroup, full_file_name=%s", full_file_name);
result = false;
}
else
{
/*Codes_SRS_FILE_WIN32_43_007: [ file_create shall register the cleanup group with the threadpool environment by calling SetThreadpoolCallbackCleanupGroup.]*/
SetThreadpoolCallbackCleanupGroup(&handle->cbe, handle->ptp_cleanup_group, on_close_threadpool_group_member);
/*Codes_SRS_FILE_WIN32_43_033: [ file_create shall create a threadpool io with the allocated FILE_HANDLE and on_file_io_complete_win32 as a callback by calling CreateThreadpoolIo]*/
handle->ptp_io = CreateThreadpoolIo(handle->h_file, on_file_io_complete_win32, NULL, &handle->cbe);
if (handle->ptp_io == NULL)
{
LogError("Failure in CreateThreadpoolIo, full_file_name=%s", full_file_name);
result = false;
}
if (!result)
{
CloseThreadpoolCleanupGroup(handle->ptp_cleanup_group);
}
}
if (!result)
{
DestroyThreadpoolEnvironment(&handle->cbe);
}
}
}
/*Codes_SRS_FILE_43_034: [ If there are any failures, file_create shall fail and return NULL. ]*/
if (!result)
{
free(handle);
}
}
}
/*Codes_SRS_FILE_WIN32_43_008: [ If there are any failures, file_create shall return NULL.]*/
if (!result)
{
return NULL;
}
/*Codes_SRS_FILE_43_038: [ file_create shall register user_report_fault_callback with argument user_report_fault_context as the callback function to be called when the callback specified by the user for a specific asynchronous operation cannot be called. ]*/
handle->user_report_fault_callback = user_report_fault_callback;
handle->user_report_fault_context = user_report_fault_context;
/*Codes_SRS_FILE_WIN32_43_009: [ file_create shall succeed and return a non - NULL value.]*/
return handle;
}
IMPLEMENT_MOCKABLE_FUNCTION(, void, file_destroy, FILE_HANDLE, handle)
{
/*Codes_SRS_FILE_43_005: [ If handle is NULL, file_destroy shall return. ]*/
/*Codes_SRS_FILE_WIN32_43_049: [ If handle is NULL, file_destroy shall return.]*/
if (handle != NULL)
{
/*Codes_SRS_FILE_43_006: [ file_destroy shall wait for all pending I/O operations to complete. ]*/
/*Codes_SRS_FILE_WIN32_43_011: [ file_destroy shall wait for all I/O to complete by calling WaitForThreadpoolIoCallbacks. ]*/
WaitForThreadpoolIoCallbacks(handle->ptp_io, FALSE);
/*Codes_SRS_FILE_WIN32_43_012: [ file_destroy shall close the cleanup group by calling CloseThreadpoolCleanupGroup. ]*/
CloseThreadpoolCleanupGroup(handle->ptp_cleanup_group);
/*Codes_SRS_FILE_WIN32_43_013: [ file_destroy shall destroy the environment by calling DestroyThreadpoolEnvironment. ]*/
DestroyThreadpoolEnvironment(&(handle->cbe));
/*Codes_SRS_FILE_43_007: [ file_destroy shall close the file handle handle. ]*/
/*Codes_SRS_FILE_WIN32_43_016: [ file_destroy shall call CloseHandle on handle->h_file ]*/
if (!CloseHandle(handle->h_file))
{
LogError("failure in CloseHandle");
}
/*Codes_SRS_FILE_WIN32_43_015: [ file_destroy shall close the threadpool IO by calling CloseThreadPoolIo. ]*/
CloseThreadpoolIo(handle->ptp_io);
/*Codes_SRS_FILE_WIN32_43_042: [ file_destroy shall free the handle.]*/
free(handle);
}
else
{
LogError("Invalid argument to file_destroy: FILE_HANDLE=%p", handle);
}
}
IMPLEMENT_MOCKABLE_FUNCTION(, FILE_WRITE_ASYNC_RESULT, file_write_async, FILE_HANDLE, handle, const unsigned char*, source, uint32_t, size, uint64_t, position, FILE_CB, user_callback, void*, user_context)
{
FILE_WRITE_ASYNC_RESULT result;
if
(
/*Codes_SRS_FILE_43_009: [ If handle is NULL then file_write_async shall fail and return FILE_WRITE_ASYNC_INVALID_ARGS. ]*/
/*Codes_SRS_FILE_WIN32_43_043: [ If handle is NULL then file_write_async shall fail and return FILE_WRITE_ASYNC_INVALID_ARGS.]*/
(handle == NULL) ||
/*Codes_SRS_FILE_43_010: [ If source is NULL then file_write_async shall fail and return FILE_WRITE_ASYNC_INVALID_ARGS. ]*/
/*Codes_SRS_FILE_WIN32_43_044: [ If source is NULL then file_write_async shall fail and return FILE_WRITE_ASYNC_INVALID_ARGS.]*/
(source == NULL) ||
/*Codes_SRS_FILE_43_012: [ If user_callback is NULL then file_write_async shall fail and return FILE_WRITE_ASYNC_INVALID_ARGS. ]*/
/*Codes_SRS_FILE_WIN32_43_045: [ If user_callback is NULL then file_write_async shall fail and return FILE_WRITE_ASYNC_INVALID_ARGS.]*/
(user_callback == NULL)||
/*Codes_SRS_FILE_43_040: [ If position + size is greater than INT64_MAX, then file_write_async shall fail and return FILE_WRITE_ASYNC_INVALID_ARGS. ]*/
/*Codes_SRS_FILE_WIN32_43_060: [ If position + size is greater than INT64_MAX, then file_write_async shall fail and return FILE_WRITE_ASYNC_INVALID_ARGS. ]*/
((position + size) > INT64_MAX)||
/*Codes_SRS_FILE_43_042: [ If size is 0 then file_write_async shall fail and return FILE_WRITE_ASYNC_INVALID_ARGS. ]*/
/*Codes_SRS_FILE_WIN32_43_061: [ If size is 0 then file_write_async shall fail and return FILE_WRITE_ASYNC_INVALID_ARGS. ]*/
(size == 0)
)
{
LogError("Invalid arguments to file_write_async: FILE_HANDLE file_handle=%p, const unsigned char* source=%p, uin32_t size=%" PRIu32 ", uint64_t position=%" PRIu64 ", FILE_CB user_callback=%p, void* user_context=%p",
handle, source, size, position, user_callback, user_context);
result = FILE_WRITE_ASYNC_INVALID_ARGS;
}
else
{
bool callback_will_be_called = false;
/*Codes_SRS_FILE_WIN32_43_018: [ file_write_async shall allocate a context to store the allocated OVERLAPPED struct, handle, size, user_callback and user_context. ]*/
FILE_WIN32_IO* io = malloc(sizeof(FILE_WIN32_IO));
if (io == NULL)
{
/*Codes_SRS_FILE_43_015: [ If there are any failures, file_write_async shall fail and return FILE_WRITE_ASYNC_ERROR. ]*/
/*Codes_SRS_FILE_WIN32_43_057: [ If there are any other failures, file_write_async shall fail and return FILE_WRITE_ASYNC_ERROR.]*/
LogError("failure in malloc");
result = FILE_WRITE_ASYNC_ERROR;
}
else
{
io->handle = handle;
/*Codes_SRS_FILE_WIN32_43_020: [ file_write_async shall allocate an OVERLAPPED struct and populate it with the created event and position. ]*/
(void)memset(&(io->ov), 0, sizeof(OVERLAPPED));
/*Codes_SRS_FILE_WIN32_43_054: [ file_write_async shall create an event by calling CreateEvent.]*/
io->ov.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (io->ov.hEvent == NULL)
{
/*Codes_SRS_FILE_43_015: [ If there are any failures, file_write_async shall fail and return FILE_WRITE_ASYNC_ERROR. ]*/
/*Codes_SRS_FILE_WIN32_43_057: [ If there are any other failures, file_write_async shall fail and return FILE_WRITE_ASYNC_ERROR.]*/
LogError("failure in CreateEvent");
result = FILE_WRITE_ASYNC_ERROR;
}
else
{
io->ov.Offset = position & 0xFFFFFFFFULL;
io->ov.OffsetHigh = position >> 32;
io->user_callback = user_callback;
io->user_context = user_context;
io->size = size;
/*Codes_SRS_FILE_WIN32_43_017: [ file_write_async shall call StartThreadpoolIo.]*/
StartThreadpoolIo(handle->ptp_io);
/*Codes_SRS_FILE_43_014: [ file_write_async shall enqueue a write request to write source's content to the position offset in the file. ]*/
/*Codes_SRS_FILE_43_041: [ If position + size is greater than the size of the file and the call to write is succesfull, file_write_async shall grow the file to accomodate the write. ]*/
/*Codes_SRS_FILE_WIN32_43_021: [ file_write_async shall call WriteFile with handle, source, size and the allocated OVERLAPPED struct.]*/
if (WriteFile(handle->h_file, source, size, NULL, &(io->ov)) == FALSE)
{
if (GetLastError() == ERROR_IO_PENDING)
{
/*Codes_SRS_FILE_43_008: [ file_write_async shall call user_call_back passing user_context and success depending on the success of the asynchronous write operation.]*/
/*Codes_SRS_FILE_43_030: [ file_write_async shall succeed and return FILE_WRITE_ASYNC_OK. ]*/
/*Codes_SRS_FILE_WIN32_43_022: [ If WriteFile fails synchronously and GetLastError indicates ERROR_IO_PENDING then file_write_async shall succeed and return FILE_WRITE_ASYNC_OK.]*/
callback_will_be_called = true;
result = FILE_WRITE_ASYNC_OK;
}
else
{
/*Codes_SRS_FILE_43_035: [ If the call to write the file fails, file_write_async shall fail and return FILE_WRITE_ASYNC_WRITE_ERROR. ]*/
/*Codes_SRS_FILE_WIN32_43_023: [ If WriteFile fails synchronously and GetLastError does not indicate ERROR_IO_PENDING then file_write_async shall fail, call CancelThreadpoolIo and return FILE_WRITE_ASYNC_WRITE_ERROR.]*/
LogError("failure in WriteFile");
CancelThreadpoolIo(handle->ptp_io);
result = FILE_WRITE_ASYNC_WRITE_ERROR;
}
}
else
{
/*Codes_SRS_FILE_43_008: [ file_write_async shall call user_call_back passing user_context and success depending on the success of the asynchronous write operation.]*/
/*Codes_SRS_FILE_43_030: [ file_write_async shall succeed and return FILE_WRITE_ASYNC_OK. ]*/
/*Codes_SRS_FILE_WIN32_43_024: [ If WriteFile succeeds synchronously then file_write_async shall succeed, call CancelThreadpoolIo, call user_callback and return FILE_WRITE_ASYNC_OK.]*/
CancelThreadpoolIo(handle->ptp_io);
user_callback(user_context, true);
result = FILE_WRITE_ASYNC_OK;
}
if (!callback_will_be_called)
{
if (!CloseHandle(io->ov.hEvent))
{
LogError("Failure in CloseHandle");
}
}
}
if (!callback_will_be_called)
{
free(io);
}
}
}
return result;
}
IMPLEMENT_MOCKABLE_FUNCTION(, FILE_READ_ASYNC_RESULT, file_read_async, FILE_HANDLE, handle, unsigned char*, destination, uint32_t, size, uint64_t, position, FILE_CB, user_callback, void*, user_context)
{
FILE_READ_ASYNC_RESULT result;
if
(
/*Codes_SRS_FILE_43_017: [ If handle is NULL then file_read_async shall fail and return FILE_READ_ASYNC_INVALID_ARGS. ]*/
/*Codes_SRS_FILE_WIN32_43_046: [ If handle is NULL then file_read_async shall fail and return FILE_READ_ASYNC_INVALID_ARGS. ]*/
(handle == NULL) ||
/*Codes_SRS_FILE_43_032: [ If destination is NULL then file_read_async shall fail and return FILE_READ_ASYNC_INVALID_ARGS. ]*/
/*Codes_SRS_FILE_WIN32_43_051: [ If destination is NULL then file_read_async shall fail and return FILE_READ_ASYNC_INVALID_ARGS. ]*/
(destination == NULL) ||
/*Codes_SRS_FILE_43_020: [ If user_callback is NULL then file_read_async shall fail and return FILE_READ_ASYNC_INVALID_ARGS. ]*/
/*Codes_SRS_FILE_WIN32_43_047: [ If user_callback is NULL then file_read_async shall fail and return FILE_READ_ASYNC_INVALID_ARGS. ]*/
(user_callback == NULL) ||
/*Codes_SRS_FILE_43_043: [ If size is 0 then file_read_async shall fail and return FILE_READ_ASYNC_INVALID_ARGS. ]*/
/*Codes_SRS_FILE_WIN32_43_062: [ If size is 0 then file_read_async shall fail and return FILE_READ_ASYNC_INVALID_ARGS. ]*/
(size == 0)
)
{
LogError("Invalid arguments to file_read_async: FILE_HANDLE file_handle=%p, unsigned char* destination=%p, uin32_t size=%" PRIu32 ", uint64_t position=%" PRIu64 ", FILE_CB user_callback=%p, void* user_context=%p",
handle, destination, size, position, user_callback, user_context);
result = FILE_READ_ASYNC_INVALID_ARGS;
}
else
{
bool callback_will_be_called = false;
/*Codes_SRS_FILE_WIN32_43_026: [ file_read_async shall allocate a context to store the allocated OVERLAPPED struct, destination, handle, size, user_callback and user_context ]*/
FILE_WIN32_IO* io = malloc(sizeof(FILE_WIN32_IO));
if (io == NULL)
{
/*Codes_SRS_FILE_43_022: [ If there are any failures then file_read_async shall fail and return FILE_READ_ASYNC_ERROR. ]*/
/*Codes_SRS_FILE_WIN32_43_058: [ If there are any other failures, file_read_async shall fail and return FILE_READ_ASYNC_ERROR. ]*/
LogError("Failure in malloc");
result = FILE_READ_ASYNC_ERROR;
}
else
{
io->handle = handle;
/*Codes_SRS_FILE_WIN32_43_028: [ file_read_async shall allocate an OVERLAPPED struct and populate it with the created event and position. ]*/
(void)memset(&(io->ov), 0, sizeof(OVERLAPPED));
/*Codes_SRS_FILE_WIN32_43_055: [ file_read_async shall create an event by calling CreateEvent. ]*/
io->ov.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (io->ov.hEvent == NULL)
{
/*Codes_SRS_FILE_43_022: [ If there are any failures then file_read_async shall fail and return FILE_READ_ASYNC_ERROR. ]*/
/*Codes_SRS_FILE_WIN32_43_058: [ If there are any other failures, file_read_async shall fail and return FILE_READ_ASYNC_ERROR. ]*/
LogError("Failure in CreateEvent");
result = FILE_READ_ASYNC_ERROR;
}
else
{
io->ov.Offset = position & 0xFFFFFFFFULL;
io->ov.OffsetHigh = position >> 32;
io->user_callback = user_callback;
io->user_context = user_context;
io->size = size;
/*Codes_SRS_FILE_43_021: [ file_read_async shall enqueue a read request to read handle's content at position offset and write it to destination. ]*/
/*Codes_SRS_FILE_43_039: [ If position + size exceeds the size of the file, user_callback shall be called with success as false. ]*/
/*Codes_SRS_FILE_WIN32_43_025: [ file_read_async shall call StartThreadpoolIo. ]*/
StartThreadpoolIo(handle->ptp_io);
/*Codes_SRS_FILE_WIN32_43_029: [ file_read_async shall call ReadFile with handle, destination, size and the allocated OVERLAPPED struct.]*/
if (ReadFile(handle->h_file, destination, size, NULL, &(io->ov)) == FALSE)
{
if (GetLastError() == ERROR_IO_PENDING)
{
/*Codes_SRS_FILE_43_016: [ file_read_async shall call user_callback passing user_context and success depending on the success of the asynchronous read operation.]*/
/*Codes_SRS_FILE_43_031: [ file_read_async shall succeed and return FILE_READ_ASYNC_OK. ]*/
/*Codes_SRS_FILE_WIN32_43_030: [ If ReadFile fails synchronously and GetLastError indicates ERROR_IO_PENDING then file_read_async shall succeed and return FILE_READ_ASYNC_OK. ]*/
callback_will_be_called = true;
result = FILE_READ_ASYNC_OK;
}
else
{
/*Codes_SRS_FILE_43_036: [ If the call to read the file fails, file_read_async shall fail and return FILE_READ_ASYNC_READ_ERROR. ]*/
/*Codes_SRS_FILE_WIN32_43_031: [ If ReadFile fails synchronously and GetLastError does not indicate ERROR_IO_PENDING then file_read_async shall fail, call CancelThreadpoolIo and return FILE_READ_ASYNC_WRITE_ERROR. ]*/
LogError("Failure in ReadFile");
CancelThreadpoolIo(handle->ptp_io);
result = FILE_READ_ASYNC_READ_ERROR;
}
}
else
{
/*Codes_SRS_FILE_43_016: [ file_read_async shall call user_callback passing user_context and success depending on the success of the asynchronous read operation.]*/
/*Codes_SRS_FILE_43_031: [ file_read_async shall succeed and return FILE_READ_ASYNC_OK. ]*/
/*Codes_SRS_FILE_WIN32_43_032: [ If ReadFile succeeds synchronously then file_read_async shall succeed, call CancelThreadpoolIo, call user_callback and return FILE_READ_ASYNC_OK. ]*/
CancelThreadpoolIo(handle->ptp_io);
user_callback(user_context, true);
result = FILE_READ_ASYNC_OK;
}
if (!callback_will_be_called)
{
if (!CloseHandle(io->ov.hEvent))
{
LogError("Failure in CloseHandle");
}
}
}
if (!callback_will_be_called)
{
free(io);
}
}
}
return result;
}
IMPLEMENT_MOCKABLE_FUNCTION(, int, file_extend, FILE_HANDLE, handle, uint64_t, desired_size)
{
(void)handle;
(void)desired_size;
/*Codes_SRS_FILE_WIN32_43_050: [ file_extend shall return 0. ]*/
return 0;
}
static void on_file_io_complete_win32(
PTP_CALLBACK_INSTANCE instance,
PVOID context,
PVOID overlapped,
ULONG io_result,
ULONG_PTR number_of_bytes_transferred,
PTP_IO io
)
{
(void)instance;
(void)context;
(void)io_result;
(void)number_of_bytes_transferred;
(void)io;
void (*callback_function)();
void* callback_context;
HANDLE handle = NULL;
bool report_fault = false;
/*Codes_SRS_FILE_WIN32_43_034: [ on_file_io_complete_win32 shall recover the file handle, the number of bytes requested by the user, user_callback and user_context from the context containing overlapped. ]*/
FILE_WIN32_IO* io_context = CONTAINING_RECORD(overlapped, FILE_WIN32_IO, ov);
if (io_context->user_callback == NULL)
{
LogError("Could not recover user-specified callback");
report_fault = true;
callback_function = (FILE_REPORT_FAULT)(io_context->handle->user_report_fault_callback);
callback_context = io_context->handle->user_report_fault_context;
}
else
{
callback_function = (FILE_CB)(io_context->user_callback);
callback_context = io_context->user_context;
handle = io_context->handle->h_file;
}
DWORD num_bytes;
/*Codes_SRS_FILE_WIN32_43_063: [ on_file_io_complete_win32 shall call GetOverlappedResult to determine if the asynchronous operation was successful. ]*/
bool overlapped_result = GetOverlappedResult(handle, overlapped, &num_bytes, FALSE);
(void)num_bytes;
/*Codes_SRS_FILE_WIN32_43_067: [ on_file_io_complete_win32 shall compare number_of_bytes_transferred to the number of bytes requested by the user. ]*/
bool all_bytes_were_transferred = (uint32_t)number_of_bytes_transferred == io_context->size;
CloseHandle(io_context->ov.hEvent);
free(io_context);
if (!overlapped_result)
{
DWORD error = GetLastError();
LogError("Error in asynchronous operation. Error code =%" PRIu32 "", error);
}
if (!all_bytes_were_transferred)
{
LogError("All bytes were not transferred.");
}
if (report_fault)
{
if(callback_function != NULL)
{
((FILE_REPORT_FAULT)callback_function)(callback_context, "Could not determine recover user_callback.");
}
}
else
{
/*Codes_SRS_FILE_WIN32_43_066: [ on_file_io_complete_win32 shall call user_callback with is_successful as true if and only if GetOverlappedResult returns true and number_of_bytes_transferred is equal to the number of bytes requested by the user. ]*/
/*Codes_SRS_FILE_WIN32_43_068: [ If either GetOverlappedResult returns false or number_of_bytes_transferred is not equal to the bytes requested by the user, on_file_io_complete_win32 shall return false. ]*/
((FILE_CB)callback_function)(callback_context, overlapped_result && all_bytes_were_transferred);
}
}

Просмотреть файл

@ -15,6 +15,7 @@ if(${run_unittests})
add_subdirectory(srw_lock_win32_ut)
add_subdirectory(reals_win32_ut)
add_subdirectory(sync_win32_ut)
add_subdirectory(file_win32_ut)
endif()
if(${run_int_tests})