diff --git a/src/Makefile.am b/src/Makefile.am index 16658ca..6775178 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -6,7 +6,7 @@ EXTRA_DIST = fprintd.xml bin_PROGRAMS = fprintd -fprintd_SOURCES = main.c manager.c device.c +fprintd_SOURCES = main.c manager.c device.c file_storage.c fprintd_LDADD = $(GLIB_LIBS) $(DBUS_GLIB_LIBS) $(FPRINT_LIBS) fprintd_CFLAGS = $(AM_CFLAGS) $(GLIB_CFLAGS) $(DBUS_GLIB_CFLAGS) $(FPRINT_CFLAGS) diff --git a/src/device.c b/src/device.c index b44bc9a..46da068 100644 --- a/src/device.c +++ b/src/device.c @@ -23,6 +23,7 @@ #include #include "fprintd.h" +#include "storage.h" static gboolean fprint_device_claim(FprintDevice *rdev, DBusGMethodInvocation *context); @@ -42,6 +43,13 @@ static gboolean fprint_device_enroll_start(FprintDevice *rdev, guint32 finger_num, GError **error); static gboolean fprint_device_enroll_stop(FprintDevice *rdev, DBusGMethodInvocation *context); +static gboolean fprint_device_set_storage_type(FprintDevice *rdev, + gint type); +static gboolean fprint_device_list_enrolled_fingers_from_storage(FprintDevice *rdev, + gchar *username, GArray **fingers, GError **error); +static gboolean fprint_device_load_print_data_from_storage(FprintDevice *rdev, + guint32 finger_num, gchar *username, guint32 *print_id, GError **error); + #include "device-dbus-glue.h" @@ -57,6 +65,7 @@ struct session_data { /* a list of loaded prints */ GSList *loaded_prints; + }; struct loaded_print { @@ -69,6 +78,9 @@ struct FprintDevicePrivate { struct fp_dscv_dev *ddev; struct fp_dev *dev; struct session_data *session; + + /* type of storage */ + int storage_type; }; typedef struct FprintDevicePrivate FprintDevicePrivate; @@ -142,6 +154,8 @@ static void device_init(GTypeInstance *instance, gpointer g_class) FprintDevice *self = (FprintDevice *) instance; FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(self); priv->id = ++last_id; + priv->storage_type = FP_FILE_STORAGE; + storages[priv->storage_type].init(); } GType fprint_device_get_type(void) @@ -495,3 +509,72 @@ static gboolean fprint_device_enroll_stop(FprintDevice *rdev, return TRUE; } +static gboolean fprint_device_set_storage_type(FprintDevice *rdev, + gint type) +{ + FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev); + + if (type >= FP_STORAGES_COUNT) return FALSE; + + storages[priv->storage_type].deinit(); + priv->storage_type = type; + storages[priv->storage_type].init(); + + return TRUE; +} + +static gboolean fprint_device_list_enrolled_fingers_from_storage(FprintDevice *rdev, + gchar *username, GArray **fingers, GError **error) +{ + FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev); + GSList *prints; + GSList *item; + GArray *ret; + + prints = storages[priv->storage_type].discover_prints(priv->dev, username); + if (!prints) { + g_set_error(error, FPRINT_ERROR, FPRINT_ERROR_DISCOVER_PRINTS, + "Failed to discover prints"); + return FALSE; + } + + ret = g_array_new(FALSE, FALSE, sizeof(int)); + for (item = prints; item; item = item->next) { + int *fingerptr = (int *)item->data; + ret = g_array_append_val(ret, *fingerptr); + } + + g_slist_free(prints); + *fingers = ret; + return TRUE; +} + +static gboolean fprint_device_load_print_data_from_storage(FprintDevice *rdev, + guint32 finger_num, gchar *username, guint32 *print_id, GError **error) +{ + FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev); + struct session_data *session = priv->session; + struct loaded_print *lprint; + struct fp_print_data *data; + int r; + + r = storages[priv->storage_type].print_data_load(priv->dev, (enum fp_finger)finger_num, + &data, (char *)username); + + if (r < 0) { + g_set_error(error, FPRINT_ERROR, FPRINT_ERROR_PRINT_LOAD, + "Print load failed with error %d", r); + return FALSE; + } + + lprint = g_slice_new(struct loaded_print); + lprint->data = data; + lprint->id = ++last_id; + session->loaded_prints = g_slist_prepend(session->loaded_prints, lprint); + + g_message("load print data finger %d for device %d = %d", + finger_num, priv->id, lprint->id); + *print_id = lprint->id; + return TRUE; +} + diff --git a/src/device.xml b/src/device.xml index 0c86987..9f6e6d9 100644 --- a/src/device.xml +++ b/src/device.xml @@ -50,6 +50,21 @@ + + + + + + + + + + + + + + + diff --git a/src/file_storage.c b/src/file_storage.c new file mode 100644 index 0000000..4ad5e62 --- /dev/null +++ b/src/file_storage.c @@ -0,0 +1,296 @@ +/* + * Simple file storage for fprintd + * Copyright (C) 2007 Daniel Drake + * Copyright (C) 2008 Vasily Khoruzhick + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + + +/* FIXME: + * This file almost duplicate data.c from libfprint + * Maybe someday data.c will be upgraded to this one ;) + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#define DIR_PERMS 0700 + +#ifndef FILE_STORAGE_PATH +#define FILE_STORAGE_PATH "/var/lib/fprint/" +#endif + +#define FP_FINGER_IS_VALID(finger) \ + ((finger) >= LEFT_THUMB && (finger) <= RIGHT_LITTLE) + +static char *get_path_to_storedir(uint16_t driver_id, uint32_t devtype, char *base_store) +{ + 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_print(uint16_t driver_id, uint32_t devtype, + enum fp_finger finger, char *base_store) +{ + char *dirpath; + char *path; + char fingername[2]; + + g_snprintf(fingername, 2, "%x", finger); + + dirpath = get_path_to_storedir(driver_id, devtype, base_store); + path = g_build_filename(dirpath, fingername, NULL); + g_free(dirpath); + return path; +} + +static char *get_path_to_print(struct fp_dev *dev, enum fp_finger finger, char *base_store) +{ + return __get_path_to_print(fp_driver_get_driver_id(fp_dev_get_driver(dev)), + fp_dev_get_devtype(dev), finger, base_store); +} + +static int file_storage_get_basestore_for_username(char *username, char **base_store) +{ + char *dirpath = FILE_STORAGE_PATH; + + *base_store = g_build_filename(dirpath, username, NULL); + return 0; +} + +/* if username == NULL function will use current username */ +int file_storage_print_data_save(struct fp_print_data *data, + enum fp_finger finger, char *username) +{ + GError *err = NULL; + char *path; + char *dirpath; + unsigned char *buf; + size_t len; + int r; + char *base_store = NULL; + + r = file_storage_get_basestore_for_username(username, &base_store); + + if (r < 0) { + return r; + } + + len = fp_print_data_get_data(data, &buf); + if (!len) { + g_free(base_store); + return -ENOMEM; + } + + path = __get_path_to_print(fp_print_data_get_driver_id(data), fp_print_data_get_devtype(data), finger, base_store); + dirpath = g_path_get_dirname(path); + r = g_mkdir_with_parents(dirpath, DIR_PERMS); + if (r < 0) { + g_free(base_store); + g_free(path); + g_free(dirpath); + return r; + } + + //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("save failed: %s", err->message); + g_error_free(err); + /* FIXME interpret error codes */ + return r; + } + + return 0; +} + +static int load_from_file(char *path, struct fp_print_data **data) +{ + gsize length; + gchar *contents; + GError *err = NULL; + struct fp_print_data *fdata; + + //fp_dbg("from %s", path); + g_file_get_contents(path, &contents, &length, &err); + if (err) { + int r = err->code; + 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 (!fdata) + return -EIO; + *data = fdata; + return 0; +} + +int file_storage_print_data_load(struct fp_dev *dev, + enum fp_finger finger, struct fp_print_data **data, char *username) +{ + gchar *path; + struct fp_print_data *fdata = NULL; + int r; + char *base_store = NULL; + + r = file_storage_get_basestore_for_username(username, &base_store); + + if (r < 0) { + return r; + } + + path = get_path_to_print(dev, finger, base_store); + r = load_from_file(path, &fdata); + g_free(path); + g_free(base_store); + if (r) + return r; + + if (!fp_dev_supports_print_data(dev, fdata)) { + fp_print_data_free(fdata); + return -EINVAL; + } + + *data = fdata; + return 0; +} + +int file_storage_print_data_delete(struct fp_dev *dev, + enum fp_finger finger, char *username) +{ + int r; + char *base_store; + + r = file_storage_get_basestore_for_username(username, &base_store); + + if (r < 0) { + return r; + } + + gchar *path = get_path_to_print(dev, finger, base_store); + + r = g_unlink(path); + g_free(path); + g_free(base_store); + + /* FIXME: cleanup empty directory */ + return r; +} + +static GSList *scan_dev_storedir(char *devpath, uint16_t driver_id, + uint32_t devtype, GSList *list) +{ + GError *err = NULL; + const gchar *ent; + + GDir *dir = g_dir_open(devpath, 0, &err); + if (!dir) { + //fp_err("opendir %s failed: %s", devpath, err->message); + g_error_free(err); + return list; + } + + while ((ent = g_dir_read_name(dir))) { + /* ent is an 1 hex character fp_finger code */ + guint64 val; + int *list_item; + gchar *endptr; + + if (*ent == 0 || strlen(ent) != 1) + continue; + + val = g_ascii_strtoull(ent, &endptr, 16); + if (endptr == ent || !FP_FINGER_IS_VALID(val)) { + //fp_dbg("skipping print file %s", ent); + continue; + } + + list_item = g_slice_new(int); + *list_item = val; + list = g_slist_prepend(list, list_item); + } + + g_dir_close(dir); + return list; +} + +GSList *file_storage_discover_prints(struct fp_dev *dev, char *username) +{ + //GDir *dir; + //const gchar *ent; + //GError *err = NULL; + GSList *list = NULL; + //GSList *elem; + char *base_store = NULL; + char *storedir = NULL; + int r; + + + r = file_storage_get_basestore_for_username(username, &base_store); + + if (r < 0) { + return NULL; + } + + storedir = get_path_to_storedir(fp_driver_get_driver_id(fp_dev_get_driver(dev)), + fp_dev_get_devtype(dev), base_store); + + g_message("Entering %s", storedir); + list = scan_dev_storedir(storedir, fp_driver_get_driver_id(fp_dev_get_driver(dev)), + fp_dev_get_devtype(dev), list); + + g_free(base_store); + g_free(storedir); + + return list; +} + +int file_storage_init(void) +{ + /* Nothing to do */ + return 0; +} + +int file_storage_deinit(void) +{ + /* Nothing to do */ + return 0; +} diff --git a/src/file_storage.h b/src/file_storage.h new file mode 100644 index 0000000..ace8234 --- /dev/null +++ b/src/file_storage.h @@ -0,0 +1,41 @@ +/* + * Simple file storage for fprintd + * Copyright (C) 2008 Vasily Khoruzhick + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#ifndef FILE_STORAGE_H + +#define FILE_STORAGE_H + +int file_storage_print_data_save(struct fp_print_data *data, + enum fp_finger finger, char *username); + + +int file_storage_print_data_load(struct fp_dev *dev, + enum fp_finger finger, struct fp_print_data **data, char *username); + +int file_storage_print_data_delete(struct fp_dev *dev, + enum fp_finger finger, char *username); + +int file_storage_init(void); + +int file_storage_deinit(void); + +GSList *file_storage_discover_prints(struct fp_dev *dev, char *username); + +#endif diff --git a/src/storage.h b/src/storage.h new file mode 100644 index 0000000..de758ed --- /dev/null +++ b/src/storage.h @@ -0,0 +1,70 @@ +/* + * Simple file storage for fprintd + * Copyright (C) 2008 Vasily Khoruzhick + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#ifndef STORAGE_H + +#define STORAGE_H + +#include "file_storage.h" + +typedef int (*storage_print_data_save)(struct fp_print_data *data, + enum fp_finger finger, char *username); +typedef int (*storage_print_data_load)(struct fp_dev *dev, + enum fp_finger finger, struct fp_print_data **data, char *username); +typedef int (*storage_print_data_delete)(struct fp_dev *dev, + enum fp_finger finger, char *username); +typedef GSList *(*storage_discover_prints)(struct fp_dev *dev, char *username); +typedef int (*storage_init)(void); +typedef int (*storage_deinit)(void); + +struct storage { + storage_init init; + storage_deinit deinit; + storage_print_data_save print_data_save; + storage_print_data_load print_data_load; + storage_print_data_delete print_data_delete; + storage_discover_prints discover_prints; +}; + +typedef struct storage fp_storage; + +enum storage_type { + FP_FILE_STORAGE = 0, + + FP_STORAGES_COUNT, +}; + +typedef enum storage_type fp_storage_type; + +fp_storage storages[FP_STORAGES_COUNT] = { + { + .init = &file_storage_init, + .deinit = &file_storage_deinit, + .print_data_save = &file_storage_print_data_save, + .print_data_load = &file_storage_print_data_load, + .print_data_delete = &file_storage_print_data_delete, + .discover_prints = &file_storage_discover_prints, + }, + +}; + + +#endif + diff --git a/tests/Makefile.am b/tests/Makefile.am index cdf5c89..aebfb16 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -17,4 +17,3 @@ manager-dbus-glue.h: ../src/manager.xml device-dbus-glue.h: ../src/device.xml dbus-binding-tool --prefix=fprint_device --mode=glib-client $< --output=$@ - diff --git a/tests/verify.c b/tests/verify.c index 265aa22..ab3eec6 100644 --- a/tests/verify.c +++ b/tests/verify.c @@ -17,6 +17,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include #include #include #include "manager-dbus-glue.h" @@ -155,7 +156,7 @@ static guint32 find_finger(DBusGProxy *dev) int fingernum; guint32 print_id; - if (!net_reactivated_Fprint_Device_list_enrolled_fingers(dev, &fingers, &error)) + if (!net_reactivated_Fprint_Device_list_enrolled_fingers_from_storage(dev, "anarsoul", &fingers, &error)) g_error("ListEnrolledFingers failed: %s", error->message); if (fingers->len == 0) { @@ -173,7 +174,7 @@ static guint32 find_finger(DBusGProxy *dev) g_array_free(fingers, TRUE); g_print("Verifying: %s\n", fingerstr(fingernum)); - if (!net_reactivated_Fprint_Device_load_print_data(dev, fingernum, &print_id, &error)) + if (!net_reactivated_Fprint_Device_load_print_data_from_storage(dev, fingernum, "anarsoul", &print_id, &error)) g_error("LoadPrintData failed: %s", error->message); return print_id;