/********************************************************/ /* ntapi: Native API core library */ /* Copyright (C) 2013--2016 Z. Gilboa */ /* Released under GPLv2 and GPLv3; see COPYING.NTAPI. */ /********************************************************/ #include #include #include #include #include "ntapi_impl.h" typedef struct nt_vms_cache_interface { nt_vms_system * vms_sys; struct dalist_ex cache; size_t alloc_size; uintptr_t buffer[1]; } nt_vms_cache_context; typedef struct _nt_vms_cache_record { void * hfile; uint32_t dev_name_hash; nt_large_integer index_number; intptr_t client_key; intptr_t server_key; } nt_vms_cache_record; int32_t __stdcall __ntapi_vms_cache_free( __in nt_vms_cache vms_cache) { int32_t status; void * region_addr; size_t region_size; /* validation */ if (!vms_cache) return NT_STATUS_INVALID_PARAMETER; /* free memory */ region_addr = vms_cache; region_size = vms_cache->alloc_size; status = __ntapi->zw_free_virtual_memory( NT_CURRENT_PROCESS_HANDLE, ®ion_addr, ®ion_size, NT_MEM_RELEASE); return status; } /* vms optional cache functions */ nt_vms_cache __stdcall __ntapi_vms_cache_alloc( __in nt_vms_system * vms_sys, __in uint32_t flags __reserved, __in void * options __reserved, __out int32_t * status __optional) { int32_t _status; void * buffer; size_t buffer_size; nt_vms_cache_context * vms_cache; /* status */ if (!status) status = &_status; /* validation */ if (!vms_sys) { *status = NT_STATUS_INVALID_PARAMETER; return (nt_vms_cache)0; } /* calculate size */ buffer_size = sizeof(nt_vms_cache_context); buffer_size += vms_sys->vms_points_cap * (sizeof(nt_vms_cache_record) - sizeof(uintptr_t)); /* allocate buffer */ *status = __ntapi->zw_allocate_virtual_memory( NT_CURRENT_PROCESS_HANDLE, &buffer, 0, &buffer_size, NT_MEM_COMMIT, NT_PAGE_READWRITE); if (*status) return (nt_vms_cache)0; /* init vms cache */ vms_cache = (nt_vms_cache_context *)buffer; vms_cache->vms_sys = vms_sys; vms_cache->alloc_size = buffer_size; /* init list */ *status = dalist_init_ex( &vms_cache->cache, sizeof(nt_vms_cache_record), 0x1000, __ntapi->zw_allocate_virtual_memory, DALIST_MEMFN_NT_ALLOCATE_VIRTUAL_MEMORY); if (*status != DALIST_OK) { *status = NT_STATUS_UNSUCCESSFUL; __ntapi_vms_cache_free(vms_cache); return (nt_vms_cache)0; } /* set list buffer */ buffer_size -= (size_t)&(((nt_vms_cache_context *)0)->buffer); *status = dalist_deposit_memory_block( &vms_cache->cache, &vms_cache->buffer, buffer_size); return vms_cache; } int32_t __stdcall __ntapi_vms_cache_record_append( __in nt_vms_cache cache, __in void * hfile, __in uint32_t dev_name_hash, __in nt_large_integer index_number, __in intptr_t client_key, __in intptr_t server_key) { int32_t status; struct dalist_node_ex * node; nt_vms_cache_record * cache_record; status = dalist_get_node_by_key( &cache->cache, &node, (uintptr_t)hfile, DALIST_NODE_TYPE_EXISTING, (uintptr_t *)0); if (status != DALIST_OK) status = NT_STATUS_INTERNAL_ERROR; else if (node) status = NT_STATUS_OBJECTID_EXISTS; else { status = dalist_get_free_node(&cache->cache,(void **)&node); if (status == DALIST_OK) { cache_record = (nt_vms_cache_record *)&node->dblock; __ntapi->tt_aligned_block_memset( node, 0, (uintptr_t)&((struct dalist_node_ex *)0)->dblock + sizeof(*cache_record)); node->key = (uintptr_t)hfile; cache_record->hfile = hfile; cache_record->dev_name_hash = dev_name_hash; cache_record->index_number.quad = index_number.quad; cache_record->client_key = client_key; cache_record->server_key = server_key; status = dalist_insert_node_by_key( &cache->cache, node); if (status != DALIST_OK) dalist_deposit_free_node( &cache->cache, node); } } return status; } int32_t __stdcall __ntapi_vms_cache_record_remove( __in nt_vms_cache cache, __in void * hfile, __in uint32_t dev_name_hash, __in nt_large_integer index_number) { int32_t status; struct dalist_node_ex * node; status = dalist_get_node_by_key( &cache->cache, &node, (uintptr_t)hfile, DALIST_NODE_TYPE_EXISTING, (uintptr_t *)0); if (status != DALIST_OK) status = NT_STATUS_INTERNAL_ERROR; else if (node) status = NT_STATUS_INVALID_PARAMETER; else { status = dalist_discard_node( &cache->cache, node); if (status != DALIST_OK) status = NT_STATUS_INTERNAL_ERROR; } return status; }