b96aade69c
Add accessor functions to the various structures
318 lines
7.5 KiB
C
318 lines
7.5 KiB
C
/*
|
|
* Fingerprint data handling and storage
|
|
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#include <config.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
|
|
#include <glib.h>
|
|
|
|
#include "fp_internal.h"
|
|
|
|
#define DIR_PERMS 0700
|
|
|
|
/* FIXME: should free this during library shutdown */
|
|
static char *base_store = NULL;
|
|
|
|
static void storage_setup(void)
|
|
{
|
|
const char *homedir;
|
|
|
|
homedir = g_getenv("HOME");
|
|
if (!homedir)
|
|
homedir = g_get_home_dir();
|
|
if (!homedir)
|
|
return;
|
|
|
|
base_store = g_build_filename(homedir, ".fprint/prints", NULL);
|
|
g_mkdir_with_parents(base_store, DIR_PERMS);
|
|
/* FIXME handle failure */
|
|
}
|
|
|
|
static const char *finger_code_to_str(enum fp_finger finger)
|
|
{
|
|
const char *names[] = {
|
|
[LEFT_THUMB] = "lthu",
|
|
[LEFT_INDEX] = "lind",
|
|
[LEFT_MIDDLE] = "lmid",
|
|
[LEFT_RING] = "lrin",
|
|
[LEFT_LITTLE] = "llit",
|
|
[RIGHT_THUMB] = "rthu",
|
|
[RIGHT_INDEX] = "rind",
|
|
[RIGHT_MIDDLE] = "rmid",
|
|
[RIGHT_RING] = "rrin",
|
|
[RIGHT_LITTLE] = "rlit",
|
|
};
|
|
if (finger < LEFT_THUMB || finger > RIGHT_LITTLE)
|
|
return NULL;
|
|
return names[finger];
|
|
}
|
|
|
|
static enum fp_print_data_type get_data_type_for_dev(struct fp_dev *dev)
|
|
{
|
|
switch (dev->drv->type) {
|
|
case DRIVER_PRIMITIVE:
|
|
return PRINT_DATA_RAW;
|
|
case DRIVER_IMAGING:
|
|
return PRINT_DATA_NBIS_MINUTIAE;
|
|
default:
|
|
fp_err("unrecognised drv type %d", dev->drv->type);
|
|
return PRINT_DATA_RAW;
|
|
}
|
|
}
|
|
|
|
static struct fp_print_data *print_data_new(uint16_t driver_id,
|
|
uint32_t devtype, enum fp_print_data_type type, size_t length)
|
|
{
|
|
struct fp_print_data *data = g_malloc(sizeof(*data) + length);
|
|
fp_dbg("length=%zd driver=%02x devtype=%04x", length, driver_id, devtype);
|
|
memset(data, 0, sizeof(*data));
|
|
data->driver_id = driver_id;
|
|
data->devtype = devtype;
|
|
data->type = type;
|
|
data->length = length;
|
|
return data;
|
|
}
|
|
|
|
struct fp_print_data *fpi_print_data_new(struct fp_dev *dev, size_t length)
|
|
{
|
|
struct fp_print_data *data = g_malloc(sizeof(*data) + length);
|
|
memset(data, 0, sizeof(*data));
|
|
return print_data_new(dev->drv->id, dev->devtype,
|
|
get_data_type_for_dev(dev), length);
|
|
}
|
|
|
|
API_EXPORTED size_t fp_print_data_get_data(struct fp_print_data *data,
|
|
unsigned char **ret)
|
|
{
|
|
struct fpi_print_data_fp1 *buf;
|
|
size_t buflen;
|
|
|
|
fp_dbg("");
|
|
|
|
buflen = sizeof(*buf) + data->length;
|
|
buf = malloc(buflen);
|
|
if (!buf)
|
|
return 0;
|
|
|
|
*ret = (unsigned char *) buf;
|
|
buf->prefix[0] = 'F';
|
|
buf->prefix[1] = 'P';
|
|
buf->prefix[2] = '1';
|
|
buf->driver_id = GUINT16_TO_LE(data->driver_id);
|
|
buf->devtype = GUINT32_TO_LE(data->devtype);
|
|
buf->data_type = data->type;
|
|
memcpy(buf->data, data->data, data->length);
|
|
return buflen;
|
|
}
|
|
|
|
API_EXPORTED struct fp_print_data *fp_print_data_from_data(unsigned char *buf,
|
|
size_t buflen)
|
|
{
|
|
struct fpi_print_data_fp1 *raw = (struct fpi_print_data_fp1 *) buf;
|
|
size_t print_data_len;
|
|
struct fp_print_data *data;
|
|
|
|
fp_dbg("buffer size %zd", buflen);
|
|
if (buflen < sizeof(*raw))
|
|
return NULL;
|
|
|
|
if (strncmp(raw->prefix, "FP1", 3) != 0) {
|
|
fp_dbg("bad header prefix");
|
|
return NULL;
|
|
}
|
|
|
|
print_data_len = buflen - sizeof(*raw);
|
|
data = print_data_new(GUINT16_FROM_LE(raw->driver_id),
|
|
GUINT32_FROM_LE(raw->devtype), raw->data_type, print_data_len);
|
|
memcpy(data->data, raw->data, print_data_len);
|
|
return data;
|
|
}
|
|
|
|
static char *__get_path_to_storedir(uint16_t driver_id, uint32_t devtype)
|
|
{
|
|
char idstr[5];
|
|
char devtypestr[9];
|
|
|
|
g_snprintf(idstr, sizeof(idstr), "%04x", driver_id);
|
|
g_snprintf(devtypestr, sizeof(devtypestr), "%08x", devtype);
|
|
|
|
return g_build_filename(base_store, idstr, devtypestr, NULL);
|
|
}
|
|
|
|
static char *get_path_to_storedir(struct fp_dev *dev)
|
|
{
|
|
return __get_path_to_storedir(dev->drv->id, dev->devtype);
|
|
}
|
|
|
|
static char *get_path_to_print(struct fp_dev *dev, const char *fingerstr)
|
|
{
|
|
char *dirpath;
|
|
char *path;
|
|
|
|
dirpath = get_path_to_storedir(dev);
|
|
path = g_build_filename(dirpath, fingerstr, NULL);
|
|
g_free(dirpath);
|
|
return path;
|
|
}
|
|
|
|
API_EXPORTED int fp_print_data_save(struct fp_print_data *data,
|
|
enum fp_finger finger)
|
|
{
|
|
GError *err = NULL;
|
|
char *path;
|
|
char *dirpath;
|
|
const char *fingerstr = finger_code_to_str(finger);
|
|
unsigned char *buf;
|
|
size_t len;
|
|
int r;
|
|
|
|
if (!fingerstr)
|
|
return -EINVAL;
|
|
|
|
if (!base_store)
|
|
storage_setup();
|
|
|
|
fp_dbg("save %s print from driver %04x", fingerstr, data->driver_id);
|
|
len = fp_print_data_get_data(data, &buf);
|
|
if (!len)
|
|
return -ENOMEM;
|
|
|
|
dirpath = __get_path_to_storedir(data->driver_id, data->devtype);
|
|
r = g_mkdir_with_parents(dirpath, DIR_PERMS);
|
|
if (r < 0) {
|
|
fp_err("couldn't create storage directory");
|
|
g_free(dirpath);
|
|
return r;
|
|
}
|
|
|
|
path = g_build_filename(dirpath, fingerstr, NULL);
|
|
fp_dbg("saving to %s", path);
|
|
g_file_set_contents(path, buf, len, &err);
|
|
free(buf);
|
|
g_free(dirpath);
|
|
g_free(path);
|
|
if (err) {
|
|
r = err->code;
|
|
fp_err("%s save failed: %s", fingerstr, err->message);
|
|
g_error_free(err);
|
|
/* FIXME interpret error codes */
|
|
return r;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
gboolean fpi_print_data_compatible(struct fp_print_data *data,
|
|
struct fp_dev *dev)
|
|
{
|
|
struct fp_driver *drv = dev->drv;
|
|
|
|
if (drv->id != data->driver_id) {
|
|
fp_dbg("driver name mismatch: %02x vs %02x", drv->id, data->driver_id);
|
|
return FALSE;
|
|
}
|
|
|
|
if (dev->devtype != data->devtype) {
|
|
fp_dbg("devtype mismatch: %04x vs %04x", dev->devtype, data->devtype);
|
|
return FALSE;
|
|
}
|
|
|
|
switch (data->type) {
|
|
case PRINT_DATA_RAW:
|
|
if (drv->type != DRIVER_PRIMITIVE) {
|
|
fp_dbg("raw data vs primitive driver mismatch");
|
|
return FALSE;
|
|
}
|
|
break;
|
|
case PRINT_DATA_NBIS_MINUTIAE:
|
|
if (drv->type != DRIVER_IMAGING) {
|
|
fp_dbg("minutiae data vs imaging driver mismatch");
|
|
return FALSE;
|
|
}
|
|
break;
|
|
default:
|
|
fp_err("unrecognised data type %d", data->type);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
API_EXPORTED int fp_print_data_load(struct fp_dev *dev,
|
|
enum fp_finger finger, struct fp_print_data **data)
|
|
{
|
|
const char *fingerstr = finger_code_to_str(finger);
|
|
gchar *path;
|
|
gsize length;
|
|
gchar *contents;
|
|
GError *err = NULL;
|
|
struct fp_print_data *fdata;
|
|
|
|
if (!fingerstr)
|
|
return -EINVAL;
|
|
|
|
if (!base_store)
|
|
storage_setup();
|
|
|
|
path = get_path_to_print(dev, fingerstr);
|
|
fp_dbg("from %s", path);
|
|
g_file_get_contents(path, &contents, &length, &err);
|
|
g_free(path);
|
|
if (err) {
|
|
int r = err->code;
|
|
fp_err("%s load failed: %s", fingerstr, err->message);
|
|
g_error_free(err);
|
|
/* FIXME interpret more error codes */
|
|
if (r == G_FILE_ERROR_NOENT)
|
|
return -ENOENT;
|
|
else
|
|
return r;
|
|
}
|
|
|
|
fdata = fp_print_data_from_data(contents, length);
|
|
g_free(contents);
|
|
|
|
if (!fpi_print_data_compatible(fdata, dev)) {
|
|
fp_err("print data is not compatible!");
|
|
return -EINVAL;
|
|
}
|
|
|
|
*data = fdata;
|
|
return 0;
|
|
}
|
|
|
|
API_EXPORTED void fp_print_data_free(struct fp_print_data *data)
|
|
{
|
|
g_free(data);
|
|
}
|
|
|
|
API_EXPORTED uint16_t fp_print_data_get_driver_id(struct fp_print_data *data)
|
|
{
|
|
return data->driver_id;
|
|
}
|
|
|
|
API_EXPORTED uint32_t fp_print_data_get_devtype(struct fp_print_data *data)
|
|
{
|
|
return data->devtype;
|
|
}
|