Esempio n. 1
0
/* Set */
eEsifError DataVault_SetValue(
	DataVaultPtr self,
	EsifDataPtr path,
	EsifDataPtr value,
	esif_flags_t flags
	)
{
	eEsifError rc = ESIF_OK;
	DataCacheEntryPtr keypair;

	if (FLAGS_TEST(self->flags, ESIF_SERVICE_CONFIG_STATIC | ESIF_SERVICE_CONFIG_READONLY)) {
		return ESIF_E_READONLY;
	}

	// Ignore value for DELETEs
	if (FLAGS_TEST(flags, ESIF_SERVICE_CONFIG_DELETE)) {
		value = NULL;
	}

	// AUTO data types or AUTO_ALLOCATE are not allowed for SET
	if (value && (value->type == ESIF_DATA_AUTO || value->buf_len == ESIF_DATA_ALLOCATE)) {
		return ESIF_E_UNSUPPORTED_RESULT_DATA_TYPE;
	}

	// Reject SETs for static-sized data types whose buffer is too small
	if (value) {
		u32 len = (u32) esif_data_type_sizeof(value->type);
		if (len > 0 && value->buf_len < len) {
			value->data_len = len;
			return ESIF_E_NEED_LARGER_BUFFER;
		}
	}

	// Write to Log
	DataVault_WriteLog(self, (flags & ESIF_SERVICE_CONFIG_DELETE ? "DELETE" : "SET"), self->name, path, flags, value);

	// Delete DataVault Key(s)?
	if (esif_ccb_strpbrk((esif_string)path->buf_ptr, "*?") != NULL) {
		if (flags & ESIF_SERVICE_CONFIG_DELETE) {
			UInt32 item = 0;
			while (item < self->cache->size) {
				if (esif_ccb_strmatch((esif_string)self->cache->elements[item].key.buf_ptr, (esif_string)path->buf_ptr)) {
					flags |= FLAGS_TEST(self->cache->elements[item].flags, ESIF_SERVICE_CONFIG_PERSIST);
					if (DataCache_DeleteValue(self->cache, (esif_string)self->cache->elements[item].key.buf_ptr) == ESIF_OK) {
						continue;
					}
				}
				item++;
			}
			goto exit;
		}
		return ESIF_E_NOT_SUPPORTED; // Keys may not contain "*" or "?"
	}

	// Read data from File
	// TODO: Change Parser Logic and Syntax instead
	if (value && value->buf_ptr && esif_ccb_strncmp((char*)value->buf_ptr, "<<", 2) == 0) {
		void *buffer  = 0;
		UInt32 buflen = 0;
		if (ReadFileIntoBuffer((char*)value->buf_ptr + 2, &buffer, &buflen) == ESIF_OK) {
			if (value->buf_len) {
				esif_ccb_free(value->buf_ptr);
			}
			value->buf_ptr = buffer;
			if (value->type == ESIF_DATA_STRING) {
				buflen++;	// Include Null Terminator
			}
			value->buf_len = value->data_len = buflen;
		} else {
			return ESIF_E_UNSPECIFIED;	// TODO: File Not Found
		}
	}

	// Get the Data Row or create it if it does not exist
	keypair = DataCache_GetValue(self->cache, (esif_string)path->buf_ptr);
	if (keypair) {	// Match Found
		// READONLY?
		if (keypair->flags & ESIF_SERVICE_CONFIG_READONLY) {
			rc = ESIF_E_READONLY;
		}
		// DELETE?
		else if (flags & ESIF_SERVICE_CONFIG_DELETE) {
			flags |= keypair->flags;
			DataCache_DeleteValue(self->cache, (esif_string)path->buf_ptr);
		} else if (value && value->buf_ptr) {
			// UPDATE
			if (keypair->value.buf_len > 0 && value->data_len != keypair->value.buf_len) {
				void *new_buf = NULL;
				u32 new_buf_len = 0;
				
				// Grow or shrink buffer if it was allocated, otherwise ask for a larger buffer
				new_buf_len = esif_ccb_max(1, value->data_len);
				new_buf= (void *)esif_ccb_realloc(keypair->value.buf_ptr, new_buf_len);

				if (new_buf == NULL) {
					return ESIF_E_NEED_LARGER_BUFFER;
				}
				else {
					keypair->value.buf_len = new_buf_len;
					keypair->value.buf_ptr = new_buf;
				}
			} 

			// Replace the File Offset stored in buf_ptr with a copy of the data for updated NOCACHE values
			if (keypair->flags & ESIF_SERVICE_CONFIG_NOCACHE && keypair->value.buf_len == 0) {
				keypair->value.buf_len = esif_ccb_max(1, value->data_len);
				keypair->value.buf_ptr = esif_ccb_malloc(value->buf_len);
			}
			keypair->flags = flags;
			keypair->value.type     = value->type;
			keypair->value.data_len = value->data_len;
			
			esif_ccb_memcpy(keypair->value.buf_ptr, value->buf_ptr, value->data_len);
			rc = ESIF_OK;
		}
	} else if (value && value->buf_ptr && !(flags & ESIF_SERVICE_CONFIG_DELETE)) {
		EsifDataPtr valueClonePtr = NULL;

		//
		// The data passed in may be in a buffer owned elsewhere, so clone the data
		//
		valueClonePtr = EsifData_Clone(value);
		if (NULL == valueClonePtr) {
			rc = ESIF_E_NO_MEMORY;
			goto exit;
		}

		DataCache_InsertValue(self->cache, (esif_string)path->buf_ptr, valueClonePtr, flags);

		EsifData_Destroy(valueClonePtr);
	}
exit:
	// If Persisted, Flush to disk
	if (rc == ESIF_OK && FLAGS_TEST(flags, ESIF_SERVICE_CONFIG_PERSIST)) {
		rc = DataVault_WriteVault(self);
	}
	return rc;
}
Esempio n. 2
0
/* Set */
eEsifError DataVault_SetValue (
	DataVaultPtr self,
	EsifDataPtr path,
	EsifDataPtr value,
	esif_flags_t flags
	)
{
	eEsifError rc = ESIF_OK;
	DataCacheEntryPtr keypair;

	if (FLAGS_TEST(self->flags, ESIF_SERVICE_CONFIG_STATIC | ESIF_SERVICE_CONFIG_READONLY)) {
		return ESIF_E_READONLY;
	}

	// Ignore value for DELETEs
	if (FLAGS_TEST(flags, ESIF_SERVICE_CONFIG_DELETE)) {
		value = NULL;
	}

	// TODO: Locking

	// AUTO data types or AUTO_ALLOCATE are not allowed for SET
	if (value && (value->type == ESIF_DATA_AUTO || value->buf_len == ESIF_DATA_ALLOCATE)) {
		return ESIF_E_UNSUPPORTED_RESULT_DATA_TYPE;
	}

	// Write to Log
	DataVault_WriteLog(self, (flags & ESIF_SERVICE_CONFIG_DELETE ? "DELETE" : "SET"), self->name, path, flags, value);

	// Delete entire DataVault?
	if (strcmp((esif_string)path->buf_ptr, "*") == 0) {
		if (flags & ESIF_SERVICE_CONFIG_DELETE) {
			DataCache_Destroy(self->cache);
			if ((self->cache = DataCache_Create()) == NULL) {
				return ESIF_E_NO_MEMORY;
			}
			DataVault_WriteVault(self);
			return ESIF_OK;
		}
		return ESIF_E_NOT_SUPPORTED;// "*" is an invalid key value
	}

	// Read data from File
	// TODO: Change Parser Logic and Syntax instead
	if (value && value->buf_ptr && esif_ccb_strncmp((char*)value->buf_ptr, "<<", 2) == 0) {
		void *buffer  = 0;
		UInt32 buflen = 0;
		if (DataVault_ReadFile(self, (char*)value->buf_ptr + 2, &buffer, &buflen) == ESIF_OK) {
			value->buf_ptr = buffer;
			if (value->type == ESIF_DATA_STRING) {
				buflen++;	// Include Null Terminator
			}
			value->buf_len = value->data_len = buflen;
		} else {
			return ESIF_E_UNSPECIFIED;	// TODO: File Not Found
		}
	}

	// Get the Data Row or create it if it does not exist
	keypair = DataCache_GetValue(self->cache, (esif_string)path->buf_ptr);
	if (keypair) {	// Match Found
		// READONLY?
		if (keypair->flags & ESIF_SERVICE_CONFIG_READONLY) {
			rc = ESIF_E_READONLY;
		}
		// DELETE?
		else if (flags & ESIF_SERVICE_CONFIG_DELETE) {
			flags |= keypair->flags;
			DataCache_Delete(self->cache, (esif_string)path->buf_ptr);
		} else if (value && value->buf_ptr) {
			// UPDATE
#ifdef ESIF_ATTR_OS_WINDOWS
			// Update Registry Value for REGKEY values if REGLINK is *NOT* specified in SET command
			if ((keypair->flags & ESIF_SERVICE_CONFIG_REGLINK) && !(flags & ESIF_SERVICE_CONFIG_REGLINK)) {
				keypair->value.type = value->type;
				rc = DataVault_WriteRegistry(self, (esif_string)keypair->value.buf_ptr, value);
			} else	// ...
#endif
			if (keypair->value.buf_len && value->data_len > keypair->value.buf_len) {
				rc = ESIF_E_NEED_LARGER_BUFFER;
			} else {
				keypair->flags = flags;
				keypair->value.type     = value->type;
				keypair->value.data_len = value->data_len;

				// Replace the File Offset stored in buf_ptr with a copy of the data for updated NOCACHE values
				if (keypair->flags & ESIF_SERVICE_CONFIG_NOCACHE && keypair->value.buf_len == 0) {
					keypair->value.buf_ptr = esif_ccb_malloc(value->data_len);
					keypair->value.buf_len = value->data_len;
				}
				esif_ccb_memcpy(keypair->value.buf_ptr, value->buf_ptr, value->data_len);
				rc = ESIF_OK;
			}
		}
	} else if (value && value->buf_ptr && !(flags & ESIF_SERVICE_CONFIG_DELETE)) {
		// Copy Key/Value Pair to new Data Row
		EsifData newkey   = {ESIF_DATA_STRING, esif_ccb_strdup((esif_string)path->buf_ptr), path->data_len, path->data_len};
		EsifData newvalue = {value->type, esif_ccb_malloc(esif_ccb_max(value->buf_len, value->data_len)), value->data_len, value->data_len};
		esif_ccb_memcpy(newvalue.buf_ptr, value->buf_ptr, value->data_len);
		DataCache_SetValue(self->cache, (esif_string)newkey.buf_ptr, newvalue, flags);
		esif_ccb_free(newkey.buf_ptr);
	}

	// If Persisted, Flush to disk
	if (rc == ESIF_OK && FLAGS_TEST(flags, ESIF_SERVICE_CONFIG_PERSIST)) {
		DataVault_WriteVault(self);
	}
	return rc;
}
Esempio n. 3
0
// Write DataVault to Disk
eEsifError DataVault_WriteVault(DataVaultPtr self)
{
	eEsifError rc = ESIF_OK;
	DataCacheEntryPtr pairPtr = NULL;
	IOStreamPtr diskStreamPtr = NULL;
	IOStreamPtr memStreamPtr = NULL;
	BytePtr memStreamBuffer = NULL;
	size_t memStreamBufSize = 0;
	UInt32 idx;
	DataCachePtr cacheClonePtr = NULL;

	if (FLAGS_TEST(self->flags, ESIF_SERVICE_CONFIG_STATIC | ESIF_SERVICE_CONFIG_READONLY)) {
		rc = ESIF_E_READONLY;
		goto exit;
	}

	if (self->stream->file.name == NULL || self->cache == NULL) {
		rc = ESIF_E_PARAMETER_IS_NULL;
		goto exit;
	}

	//
	// As the cache data can be modified while writing the data vault (due to
	// non-cached values), we create a clone of the current cache so that we can
	// fall back to it in case of a failure.
	//
	cacheClonePtr = DataCache_Clone(self->cache);
	if ((NULL == cacheClonePtr) && (self->cache != NULL)) {
		rc = ESIF_E_NO_MEMORY;
		goto exit;
	}

	//
	// Use a memory stream for creation before writing the final output to a file
	//
	memStreamPtr = IOStream_Create();
	if (!memStreamPtr) {
		rc = ESIF_E_NO_MEMORY;
		goto exit;
	}
	
	if (IOStream_SetMemory(memStreamPtr, NULL, 0) != EOK) {
		rc = ESIF_E_NO_MEMORY;
		goto exit;
	}

	//
	// If any rows contain NOCACHE PERSIST values, we need to read them from the
	// original file before we overwrite it
	//
	diskStreamPtr = IOStream_Create();
	if (diskStreamPtr == NULL) {
		rc = ESIF_E_NO_MEMORY;
		goto exit;
	}

	if (IOStream_Seek(memStreamPtr, sizeof(DataVaultHeader), SEEK_CUR) != EOK) {
		rc = ESIF_E_IO_ERROR;
		goto exit;
	}

	//
	// Write the key/value pairs to the memory stream for each data category
	// Fill in the data header for each category after the key/value pairs are written
	// Note: Only write persisted data
	//

	// Write All Persisted Rows from Sorted List to DataVault
	for (idx = 0; rc == ESIF_OK && idx < self->cache->size; idx++) {

		pairPtr = &self->cache->elements[idx];

		if (!(pairPtr->flags & ESIF_SERVICE_CONFIG_PERSIST)) {
			continue;
		}

		rc = DataVault_WriteKeyValuePair(self, pairPtr, memStreamPtr);
		if (rc != ESIF_OK) {
			goto exit;
		}
	}

	//
	// Now go back and complete the headers
	// Fill in and write the main header
	//

	if (IOStream_Open(memStreamPtr) != EOK) {
		rc = ESIF_E_IO_ERROR;
		goto exit;
	}

	DataVaultHeader header = { 0 };
	esif_ccb_memcpy(&header.signature, ESIFDV_SIGNATURE, sizeof(header.signature));
	header.headersize = sizeof(header);
	header.version = ESIFDV_VERSION(1, 0, ESIFDV_REVISION);
	header.flags = self->flags;

	if (IOStream_Write(memStreamPtr, &header, sizeof(header)) != sizeof(header)) {
		rc = ESIF_E_IO_ERROR;
		goto exit;
	}

	memStreamBuffer = IOStream_GetMemoryBuffer(memStreamPtr);
	memStreamBufSize = IOStream_GetSize(memStreamPtr);

	//
	// Now write the memory stream to the disk
	//
	if (rc == ESIF_OK && IOStream_OpenFile(diskStreamPtr, self->stream->file.name, "wb") != EOK) {
		rc = ESIF_E_IO_OPEN_FAILED;
		goto exit;
	}

	if (rc == ESIF_OK && (IOStream_Write(diskStreamPtr, memStreamBuffer, memStreamBufSize) != memStreamBufSize)) {
		rc = ESIF_E_IO_ERROR;
		goto exit;
	}
exit:
	IOStream_Destroy(diskStreamPtr);
	IOStream_Destroy(memStreamPtr);

	if (rc != ESIF_OK && cacheClonePtr != NULL) {
		DataCache_Destroy(self->cache);
		self->cache = cacheClonePtr;
	} else {
		DataCache_Destroy(cacheClonePtr);
	}

	return rc;
}
Esempio n. 4
0
// Write DataVault to Disk
eEsifError DataVault_WriteVault (DataVaultPtr self)
{
	eEsifError rc = ESIF_E_NOT_FOUND;
	DataVaultHeader header;
	struct esif_ccb_file dv_file    = {0};
	struct esif_ccb_file dv_filebak = {0};
	IOStreamPtr vault    = 0;
	IOStreamPtr vaultBak = 0;
	u32 idx;

	if (FLAGS_TEST(self->flags, ESIF_SERVICE_CONFIG_STATIC | ESIF_SERVICE_CONFIG_READONLY)) {
		return ESIF_E_READONLY;
	}

	// TODO: Locking
	vault = IOStream_Create();
	if (!vault) {
		return ESIF_E_NO_MEMORY;
	}

	// If any rows contain NOCACHE PERSIST values, we need to make a copy the original DataVault while creating the new one
	// esif_ccb_sprintf(MAX_PATH, dv_file.filename, "%s%s", esif_build_path(dv_file.filename, MAX_PATH, NULL, self->name), ESIFDV_FILEEXT);
	esif_ccb_sprintf(MAX_PATH, dv_file.filename, "%s%s%s", ESIFDV_DIR, self->name, ESIFDV_FILEEXT);

	for (idx = 0; idx < self->cache->size; idx++)
		if (FLAGS_TESTALL(self->cache->elements[idx].flags, ESIF_SERVICE_CONFIG_NOCACHE | ESIF_SERVICE_CONFIG_PERSIST) &&
			self->cache->elements[idx].value.buf_len == 0) {
			struct stat filebak_stat = {0};
            esif_ccb_sprintf(MAX_PATH, dv_filebak.filename, "%s%s%s", ESIFDV_DIR, self->name, ESIFDV_BAKFILEEXT);

			// Delete BAK file if it exists
			if (esif_ccb_stat(dv_filebak.filename, &filebak_stat) == 0) {
				esif_ccb_unlink(dv_filebak.filename);
			}
			if (esif_ccb_rename(dv_file.filename, dv_filebak.filename) == 0) {
				if ((vaultBak = IOStream_Create()) == NULL) {
					rc = ESIF_E_NO_MEMORY;
				}
				if (!vaultBak || IOStream_OpenFile(vaultBak, dv_filebak.filename, "rb") != 0) {
					IOStream_Destroy(vault);
					IOStream_Destroy(vaultBak);
					return rc;
				}
			}
			break;
		}

	// Create DataVault, Overwrite if necessary
	IOStream_SetFile(vault, self->stream->file.name, "wb");
	if (IOStream_Open(vault) != 0) {
		if (vaultBak) {
			IOStream_Destroy(vaultBak);
			esif_ccb_unlink(dv_filebak.filename);
		}
		IOStream_Destroy(vault);
		return rc;
	}

	// Create File Header
	memset(&header, 0, sizeof(header));
	esif_ccb_memcpy(&header.signature, ESIFDV_SIGNATURE, sizeof(header.signature));
	header.headersize = sizeof(header);
	header.version    = ESIFDV_VERSION(ESIFDV_MAJOR_VERSION, ESIFDV_MINOR_VERSION, ESIFDV_REVISION);
	header.flags = 0;	// TODO: get from self->flags

	// Write File Header
	IOStream_Seek(vault, 0, SEEK_SET);
	IOStream_Write(vault, &header, sizeof(header));
	rc = ESIF_OK;

	// Write All Persisted Rows from Sorted List to DataVault
	for (idx = 0; idx < self->cache->size; idx++) {
		DataCacheEntryPtr keypair = &self->cache->elements[idx];
		if (keypair->flags & ESIF_SERVICE_CONFIG_PERSIST) {
			UInt8 *buffer     = 0;
			UInt32 buffer_len = 0;
			UInt32 byte = 0;

			IOStream_Write(vault, &keypair->flags, sizeof(keypair->flags));
			IOStream_Write(vault, &keypair->key.data_len, sizeof(keypair->key.data_len));
			IOStream_Write(vault, keypair->key.buf_ptr, keypair->key.data_len);

			IOStream_Write(vault, &keypair->value.type, sizeof(keypair->value.type));
			IOStream_Write(vault, &keypair->value.data_len, sizeof(keypair->value.data_len));

			// Read NOCACHE Entries from Backup file
			if (keypair->flags & ESIF_SERVICE_CONFIG_NOCACHE) {
				size_t offset = IOStream_GetOffset(vault);

				// Read Block from BAK file
				if (keypair->value.buf_len == 0) {
					size_t bakoffset = (size_t)keypair->value.buf_ptr;
					buffer     = (UInt8*)esif_ccb_malloc(keypair->value.data_len);
					buffer_len = keypair->value.data_len;
					if (!buffer) {
						rc = ESIF_E_NO_MEMORY;
						break;
					}
					if (IOStream_Seek(vaultBak, bakoffset, SEEK_SET) != 0 || IOStream_Read(vaultBak, buffer, buffer_len) != buffer_len) {
						esif_ccb_free(buffer);
						rc = ESIF_E_UNSPECIFIED;// TODO: ESIF_E_IOERROR;
						break;
					}
					keypair->value.buf_ptr = (void*)offset;
				}
				// Convert internal storage to NOCACHE
				else {
					buffer     = (UInt8*)keypair->value.buf_ptr;
					buffer_len = keypair->value.data_len;
					keypair->value.buf_ptr = (void*)offset;
					keypair->value.buf_len = 0;
				}
			}

			// Encrypt Data?
			if (keypair->flags & ESIF_SERVICE_CONFIG_ENCRYPT) {
				if (!buffer) {
					buffer     = (UInt8*)esif_ccb_malloc(keypair->value.data_len);
					buffer_len = keypair->value.data_len;
					if (!buffer) {
						rc = ESIF_E_NO_MEMORY;
						break;
					}
				}
				for (byte = 0; byte < keypair->value.data_len; byte++)
					buffer[byte] = ~((UInt8*)(keypair->value.buf_ptr))[byte];
			}

			if (buffer) {
				IOStream_Write(vault, buffer, buffer_len);
				esif_ccb_free(buffer);
			} else {
				IOStream_Write(vault, keypair->value.buf_ptr, keypair->value.data_len);
			}
		}
	}

	// Rollback on Error
	if (rc != ESIF_OK) {
		IOStream_Destroy(vaultBak);
		IOStream_Destroy(vault);
		esif_ccb_unlink(dv_file.filename);
		IGNORE_RESULT(esif_ccb_rename(dv_filebak.filename, dv_file.filename));
		return rc;
	}
	// Remove BAK file and Commit
	if (vaultBak) {
		IOStream_Close(vaultBak);
		esif_ccb_unlink(dv_filebak.filename);
		IOStream_Destroy(vaultBak);
	}
	IOStream_Close(vault);
	IOStream_Destroy(vault);
	return rc;
}