1 /*
2  * Fingerprint data handling and storage
3  * Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19 
20 #include <config.h>
21 #include <errno.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <unistd.h>
27 
28 #include <glib.h>
29 #include <glib/gstdio.h>
30 
31 #include "fp_internal.h"
32 
33 #define DIR_PERMS 0700
34 
35 /** @defgroup print_data Stored prints
36  * Stored prints are represented by a structure named <tt>fp_print_data</tt>.
37  * Stored prints are originally obtained from an enrollment function such as
38  * fp_enroll_finger().
39  *
40  * This page documents the various operations you can do with a stored print.
41  * Note that by default, "stored prints" are not actually stored anywhere
42  * except in RAM. For the simple scenarios, libfprint provides a simple API
43  * for you to save and load the stored prints referring to a single user in
44  * their home directory. For more advanced users, libfprint provides APIs for
45  * you to convert print data to a byte string, and to reconstruct stored prints
46  * from such data at a later point. You are welcome to store these byte strings
47  * in any fashion that suits you.
48  */
49 
50 static char *base_store = NULL;
51 
storage_setup(void)52 static void storage_setup(void)
53 {
54 	const char *homedir;
55 
56 	homedir = g_getenv("HOME");
57 	if (!homedir)
58 		homedir = g_get_home_dir();
59 	if (!homedir)
60 		return;
61 
62 	base_store = g_build_filename(homedir, ".fprint/prints", NULL);
63 	g_mkdir_with_parents(base_store, DIR_PERMS);
64 	/* FIXME handle failure */
65 }
66 
fpi_data_exit(void)67 void fpi_data_exit(void)
68 {
69 	g_free(base_store);
70 }
71 
72 #define FP_FINGER_IS_VALID(finger) \
73 	((finger) >= LEFT_THUMB && (finger) <= RIGHT_LITTLE)
74 
75 /* for debug messages only */
76 #ifdef ENABLE_DEBUG_LOGGING
finger_num_to_str(enum fp_finger finger)77 static const char *finger_num_to_str(enum fp_finger finger)
78 {
79 	const char *names[] = {
80 		[LEFT_THUMB] = "left thumb",
81 		[LEFT_INDEX] = "left index",
82 		[LEFT_MIDDLE] = "left middle",
83 		[LEFT_RING] = "left ring",
84 		[LEFT_LITTLE] = "left little",
85 		[RIGHT_THUMB] = "right thumb",
86 		[RIGHT_INDEX] = "right index",
87 		[RIGHT_MIDDLE] = "right middle",
88 		[RIGHT_RING] = "right ring",
89 		[RIGHT_LITTLE] = "right little",
90 	};
91 	if (!FP_FINGER_IS_VALID(finger))
92 		return "UNKNOWN";
93 	return names[finger];
94 }
95 #endif
96 
print_data_new(uint16_t driver_id,uint32_t devtype,enum fp_print_data_type type)97 static struct fp_print_data *print_data_new(uint16_t driver_id,
98 	uint32_t devtype, enum fp_print_data_type type)
99 {
100 	struct fp_print_data *data = g_malloc0(sizeof(*data));
101 	fp_dbg("driver=%02x devtype=%04x", driver_id, devtype);
102 	data->driver_id = driver_id;
103 	data->devtype = devtype;
104 	data->type = type;
105 	return data;
106 }
107 
fpi_print_data_item_free(struct fp_print_data_item * item)108 void fpi_print_data_item_free(struct fp_print_data_item *item)
109 {
110 	g_free(item);
111 }
112 
fpi_print_data_item_new(size_t length)113 struct fp_print_data_item *fpi_print_data_item_new(size_t length)
114 {
115 	struct fp_print_data_item *item = g_malloc(sizeof(*item) + length);
116 	item->length = length;
117 
118 	return item;
119 }
120 
fpi_print_data_new(struct fp_dev * dev)121 struct fp_print_data *fpi_print_data_new(struct fp_dev *dev)
122 {
123 	return print_data_new(dev->drv->id, dev->devtype,
124 		fpi_driver_get_data_type(dev->drv));
125 }
126 
127 /** \ingroup print_data
128  * Convert a stored print into a unified representation inside a data buffer.
129  * You can then store this data buffer in any way that suits you, and load
130  * it back at some later time using fp_print_data_from_data().
131  * \param data the stored print
132  * \param ret output location for the data buffer. Must be freed with free()
133  * after use.
134  * \returns the size of the freshly allocated buffer, or 0 on error.
135  */
fp_print_data_get_data(struct fp_print_data * data,unsigned char ** ret)136 API_EXPORTED size_t fp_print_data_get_data(struct fp_print_data *data,
137 	unsigned char **ret)
138 {
139 	struct fpi_print_data_fp2 *out_data;
140 	struct fpi_print_data_item_fp2 *out_item;
141 	struct fp_print_data_item *item;
142 	size_t buflen = 0;
143 	GSList *list_item;
144 	unsigned char *buf;
145 
146 	fp_dbg("");
147 
148 	list_item = data->prints;
149 	while (list_item) {
150 		item = list_item->data;
151 		buflen += sizeof(*out_item);
152 		buflen += item->length;
153 		list_item = g_slist_next(list_item);
154 	}
155 
156 	buflen += sizeof(*out_data);
157 	out_data = g_malloc(buflen);
158 
159 	*ret = (unsigned char *) out_data;
160 	buf = out_data->data;
161 	out_data->prefix[0] = 'F';
162 	out_data->prefix[1] = 'P';
163 	out_data->prefix[2] = '2';
164 	out_data->driver_id = GUINT16_TO_LE(data->driver_id);
165 	out_data->devtype = GUINT32_TO_LE(data->devtype);
166 	out_data->data_type = data->type;
167 
168 	list_item = data->prints;
169 	while (list_item) {
170 		item = list_item->data;
171 		out_item = (struct fpi_print_data_item_fp2 *)buf;
172 		out_item->length = GUINT32_TO_LE(item->length);
173 		/* FIXME: fp_print_data_item->data content is not endianess agnostic */
174 		memcpy(out_item->data, item->data, item->length);
175 		buf += sizeof(*out_item);
176 		buf += item->length;
177 		list_item = g_slist_next(list_item);
178 	}
179 
180 	return buflen;
181 }
182 
fpi_print_data_from_fp1_data(unsigned char * buf,size_t buflen)183 static struct fp_print_data *fpi_print_data_from_fp1_data(unsigned char *buf,
184 	size_t buflen)
185 {
186 	size_t print_data_len;
187 	struct fp_print_data *data;
188 	struct fp_print_data_item *item;
189 	struct fpi_print_data_fp2 *raw = (struct fpi_print_data_fp2 *) buf;
190 
191 	print_data_len = buflen - sizeof(*raw);
192 	data = print_data_new(GUINT16_FROM_LE(raw->driver_id),
193 		GUINT32_FROM_LE(raw->devtype), raw->data_type);
194 	item = fpi_print_data_item_new(print_data_len);
195 	/* FIXME: fp_print_data->data content is not endianess agnostic */
196 	memcpy(item->data, raw->data, print_data_len);
197 	data->prints = g_slist_prepend(data->prints, item);
198 
199 	return data;
200 }
201 
fpi_print_data_from_fp2_data(unsigned char * buf,size_t buflen)202 static struct fp_print_data *fpi_print_data_from_fp2_data(unsigned char *buf,
203 	size_t buflen)
204 {
205 	size_t total_data_len, item_len;
206 	struct fp_print_data *data;
207 	struct fp_print_data_item *item;
208 	struct fpi_print_data_fp2 *raw = (struct fpi_print_data_fp2 *) buf;
209 	unsigned char *raw_buf;
210 	struct fpi_print_data_item_fp2 *raw_item;
211 
212 	total_data_len = buflen - sizeof(*raw);
213 	data = print_data_new(GUINT16_FROM_LE(raw->driver_id),
214 		GUINT32_FROM_LE(raw->devtype), raw->data_type);
215 	raw_buf = raw->data;
216 	while (total_data_len) {
217 		if (total_data_len < sizeof(*raw_item))
218 			break;
219 		total_data_len -= sizeof(*raw_item);
220 
221 		raw_item = (struct fpi_print_data_item_fp2 *)raw_buf;
222 		item_len = GUINT32_FROM_LE(raw_item->length);
223 		fp_dbg("item len %d, total_data_len %d", item_len, total_data_len);
224 		if (total_data_len < item_len) {
225 			fp_err("corrupted fingerprint data");
226 			break;
227 		}
228 		total_data_len -= item_len;
229 
230 		item = fpi_print_data_item_new(item_len);
231 		/* FIXME: fp_print_data->data content is not endianess agnostic */
232 		memcpy(item->data, raw_item->data, item_len);
233 		data->prints = g_slist_prepend(data->prints, item);
234 
235 		raw_buf += sizeof(*raw_item);
236 		raw_buf += item_len;
237 	}
238 
239 	if (g_slist_length(data->prints) == 0) {
240 		fp_print_data_free(data);
241 		data = NULL;
242 	}
243 
244 	return data;
245 
246 }
247 
248 /** \ingroup print_data
249  * Load a stored print from a data buffer. The contents of said buffer must
250  * be the untouched contents of a buffer previously supplied to you by the
251  * fp_print_data_get_data() function.
252  * \param buf the data buffer
253  * \param buflen the length of the buffer
254  * \returns the stored print represented by the data, or NULL on error. Must
255  * be freed with fp_print_data_free() after use.
256  */
fp_print_data_from_data(unsigned char * buf,size_t buflen)257 API_EXPORTED struct fp_print_data *fp_print_data_from_data(unsigned char *buf,
258 	size_t buflen)
259 {
260 	struct fpi_print_data_fp2 *raw = (struct fpi_print_data_fp2 *) buf;
261 
262 	fp_dbg("buffer size %zd", buflen);
263 	if (buflen < sizeof(*raw))
264 		return NULL;
265 
266 	if (strncmp(raw->prefix, "FP1", 3) == 0) {
267 		return fpi_print_data_from_fp1_data(buf, buflen);
268 	} else if (strncmp(raw->prefix, "FP2", 3) == 0) {
269 		return fpi_print_data_from_fp2_data(buf, buflen);
270 	} else {
271 		fp_dbg("bad header prefix");
272 	}
273 
274 	return NULL;
275 }
276 
get_path_to_storedir(uint16_t driver_id,uint32_t devtype)277 static char *get_path_to_storedir(uint16_t driver_id, uint32_t devtype)
278 {
279 	char idstr[5];
280 	char devtypestr[9];
281 
282 	g_snprintf(idstr, sizeof(idstr), "%04x", driver_id);
283 	g_snprintf(devtypestr, sizeof(devtypestr), "%08x", devtype);
284 
285 	return g_build_filename(base_store, idstr, devtypestr, NULL);
286 }
287 
__get_path_to_print(uint16_t driver_id,uint32_t devtype,enum fp_finger finger)288 static char *__get_path_to_print(uint16_t driver_id, uint32_t devtype,
289 	enum fp_finger finger)
290 {
291 	char *dirpath;
292 	char *path;
293 	char fingername[2];
294 
295 	g_snprintf(fingername, 2, "%x", finger);
296 
297 	dirpath = get_path_to_storedir(driver_id, devtype);
298 	path = g_build_filename(dirpath, fingername, NULL);
299 	g_free(dirpath);
300 	return path;
301 }
302 
get_path_to_print(struct fp_dev * dev,enum fp_finger finger)303 static char *get_path_to_print(struct fp_dev *dev, enum fp_finger finger)
304 {
305 	return __get_path_to_print(dev->drv->id, dev->devtype, finger);
306 }
307 
308 /** \ingroup print_data
309  * Saves a stored print to disk, assigned to a specific finger. Even though
310  * you are limited to storing only the 10 human fingers, this is a
311  * per-device-type limit. For example, you can store the users right index
312  * finger from a DigitalPersona scanner, and you can also save the right index
313  * finger from a UPEK scanner. When you later come to load the print, the right
314  * one will be automatically selected.
315  *
316  * This function will unconditionally overwrite a fingerprint previously
317  * saved for the same finger and device type. The print is saved in a hidden
318  * directory beneath the current user's home directory.
319  * \param data the stored print to save to disk
320  * \param finger the finger that this print corresponds to
321  * \returns 0 on success, non-zero on error.
322  */
fp_print_data_save(struct fp_print_data * data,enum fp_finger finger)323 API_EXPORTED int fp_print_data_save(struct fp_print_data *data,
324 	enum fp_finger finger)
325 {
326 	GError *err = NULL;
327 	char *path;
328 	char *dirpath;
329 	unsigned char *buf;
330 	size_t len;
331 	int r;
332 
333 	if (!base_store)
334 		storage_setup();
335 
336 	fp_dbg("save %s print from driver %04x", finger_num_to_str(finger),
337 		data->driver_id);
338 	len = fp_print_data_get_data(data, &buf);
339 	if (!len)
340 		return -ENOMEM;
341 
342 	path = __get_path_to_print(data->driver_id, data->devtype, finger);
343 	dirpath = g_path_get_dirname(path);
344 	r = g_mkdir_with_parents(dirpath, DIR_PERMS);
345 	if (r < 0) {
346 		fp_err("couldn't create storage directory");
347 		g_free(path);
348 		g_free(dirpath);
349 		return r;
350 	}
351 
352 	fp_dbg("saving to %s", path);
353 	g_file_set_contents(path, buf, len, &err);
354 	free(buf);
355 	g_free(dirpath);
356 	g_free(path);
357 	if (err) {
358 		r = err->code;
359 		fp_err("save failed: %s", err->message);
360 		g_error_free(err);
361 		/* FIXME interpret error codes */
362 		return r;
363 	}
364 
365 	return 0;
366 }
367 
fpi_print_data_compatible(uint16_t driver_id1,uint32_t devtype1,enum fp_print_data_type type1,uint16_t driver_id2,uint32_t devtype2,enum fp_print_data_type type2)368 gboolean fpi_print_data_compatible(uint16_t driver_id1, uint32_t devtype1,
369 	enum fp_print_data_type type1, uint16_t driver_id2, uint32_t devtype2,
370 	enum fp_print_data_type type2)
371 {
372 	if (driver_id1 != driver_id2) {
373 		fp_dbg("driver ID mismatch: %02x vs %02x", driver_id1, driver_id2);
374 		return FALSE;
375 	}
376 
377 	if (devtype1 != devtype2) {
378 		fp_dbg("devtype mismatch: %04x vs %04x", devtype1, devtype2);
379 		return FALSE;
380 	}
381 
382 	if (type1 != type2) {
383 		fp_dbg("type mismatch: %d vs %d", type1, type2);
384 		return FALSE;
385 	}
386 
387 	return TRUE;
388 }
389 
load_from_file(char * path,struct fp_print_data ** data)390 static int load_from_file(char *path, struct fp_print_data **data)
391 {
392 	gsize length;
393 	gchar *contents;
394 	GError *err = NULL;
395 	struct fp_print_data *fdata;
396 
397 	fp_dbg("from %s", path);
398 	g_file_get_contents(path, &contents, &length, &err);
399 	if (err) {
400 		int r = err->code;
401 		fp_err("%s load failed: %s", path, err->message);
402 		g_error_free(err);
403 		/* FIXME interpret more error codes */
404 		if (r == G_FILE_ERROR_NOENT)
405 			return -ENOENT;
406 		else
407 			return r;
408 	}
409 
410 	fdata = fp_print_data_from_data(contents, length);
411 	g_free(contents);
412 	if (!fdata)
413 		return -EIO;
414 	*data = fdata;
415 	return 0;
416 }
417 
418 /** \ingroup print_data
419  * Loads a previously stored print from disk. The print must have been saved
420  * earlier using the fp_print_data_save() function.
421  *
422  * A return code of -ENOENT indicates that the fingerprint requested could not
423  * be found. Other error codes (both positive and negative) are possible for
424  * obscure error conditions (e.g. corruption).
425  *
426  * \param dev the device you are loading the print for
427  * \param finger the finger of the file you are loading
428  * \param data output location to put the corresponding stored print. Must be
429  * freed with fp_print_data_free() after use.
430  * \returns 0 on success, non-zero on error
431  */
fp_print_data_load(struct fp_dev * dev,enum fp_finger finger,struct fp_print_data ** data)432 API_EXPORTED int fp_print_data_load(struct fp_dev *dev,
433 	enum fp_finger finger, struct fp_print_data **data)
434 {
435 	gchar *path;
436 	struct fp_print_data *fdata;
437 	int r;
438 
439 	if (!base_store)
440 		storage_setup();
441 
442 	path = get_path_to_print(dev, finger);
443 	r = load_from_file(path, &fdata);
444 	g_free(path);
445 	if (r)
446 		return r;
447 
448 	if (!fp_dev_supports_print_data(dev, fdata)) {
449 		fp_err("print data is not compatible!");
450 		fp_print_data_free(fdata);
451 		return -EINVAL;
452 	}
453 
454 	*data = fdata;
455 	return 0;
456 }
457 
458 /** \ingroup print_data
459  * Removes a stored print from disk previously saved with fp_print_data_save().
460  * \param dev the device that the print belongs to
461  * \param finger the finger of the file you are deleting
462  * \returns 0 on success, negative on error
463  */
fp_print_data_delete(struct fp_dev * dev,enum fp_finger finger)464 API_EXPORTED int fp_print_data_delete(struct fp_dev *dev,
465 	enum fp_finger finger)
466 {
467 	int r;
468 	gchar *path = get_path_to_print(dev, finger);
469 
470 	fp_dbg("remove finger %d at %s", finger, path);
471 	r = g_unlink(path);
472 	g_free(path);
473 	if (r < 0)
474 		fp_dbg("unlink failed with error %d", r);
475 
476 	/* FIXME: cleanup empty directory */
477 	return r;
478 }
479 
480 /** \ingroup print_data
481  * Attempts to load a stored print based on a \ref dscv_print
482  * "discovered print" record.
483  *
484  * A return code of -ENOENT indicates that the file referred to by the
485  * discovered print could not be found. Other error codes (both positive and
486  * negative) are possible for obscure error conditions (e.g. corruption).
487  *
488  * \param print the discovered print
489  * \param data output location to point to the corresponding stored print. Must
490  * be freed with fp_print_data_free() after use.
491  * \returns 0 on success, non-zero on error.
492  */
fp_print_data_from_dscv_print(struct fp_dscv_print * print,struct fp_print_data ** data)493 API_EXPORTED int fp_print_data_from_dscv_print(struct fp_dscv_print *print,
494 	struct fp_print_data **data)
495 {
496 	return load_from_file(print->path, data);
497 }
498 
499 /** \ingroup print_data
500  * Frees a stored print. Must be called when you are finished using the print.
501  * \param data the stored print to destroy. If NULL, function simply returns.
502  */
fp_print_data_free(struct fp_print_data * data)503 API_EXPORTED void fp_print_data_free(struct fp_print_data *data)
504 {
505 	if (data)
506 		g_slist_free_full(data->prints, (GDestroyNotify)fpi_print_data_item_free);
507 	g_free(data);
508 }
509 
510 /** \ingroup print_data
511  * Gets the \ref driver_id "driver ID" for a stored print. The driver ID
512  * indicates which driver the print originally came from. The print is
513  * only usable with a device controlled by that driver.
514  * \param data the stored print
515  * \returns the driver ID of the driver compatible with the print
516  */
fp_print_data_get_driver_id(struct fp_print_data * data)517 API_EXPORTED uint16_t fp_print_data_get_driver_id(struct fp_print_data *data)
518 {
519 	return data->driver_id;
520 }
521 
522 /** \ingroup print_data
523  * Gets the \ref devtype "devtype" for a stored print. The devtype represents
524  * which type of device under the parent driver is compatible with the print.
525  * \param data the stored print
526  * \returns the devtype of the device range compatible with the print
527  */
fp_print_data_get_devtype(struct fp_print_data * data)528 API_EXPORTED uint32_t fp_print_data_get_devtype(struct fp_print_data *data)
529 {
530 	return data->devtype;
531 }
532 
533 /** @defgroup dscv_print Print discovery
534  * The \ref print_data "stored print" documentation detailed a simple API
535  * for storing per-device prints for a single user, namely
536  * fp_print_data_save(). It also detailed a load function,
537  * fp_print_data_load(), but usage of this function is limited to scenarios
538  * where you know which device you would like to use, and you know which
539  * finger you are looking to verify.
540  *
541  * In other cases, it would be more useful to be able to enumerate all
542  * previously saved prints, potentially even before device discovery. These
543  * functions are designed to offer this functionality to you.
544  *
545  * Discovered prints are stored in a <tt>dscv_print</tt> structure, and you
546  * can use functions documented below to access some information about these
547  * prints. You can determine if a discovered print appears to be compatible
548  * with a device using functions such as fp_dscv_dev_supports_dscv_print() and
549  * fp_dev_supports_dscv_print().
550  *
551  * When you are ready to use the print, you can load it into memory in the form
552  * of a stored print by using the fp_print_data_from_dscv_print() function.
553  *
554  * You may have noticed the use of the word "appears" in the above paragraphs.
555  * libfprint performs print discovery simply by examining the file and
556  * directory structure of libfprint's private data store. It does not examine
557  * the actual prints themselves. Just because a print has been discovered
558  * and appears to be compatible with a certain device does not necessarily mean
559  * that it is usable; when you come to load or use it, under unusual
560  * circumstances it may turn out that the print is corrupt or not for the
561  * device that it appeared to be. Also, it is possible that the print may have
562  * been deleted by the time you come to load it.
563  */
564 
scan_dev_store_dir(char * devpath,uint16_t driver_id,uint32_t devtype,GSList * list)565 static GSList *scan_dev_store_dir(char *devpath, uint16_t driver_id,
566 	uint32_t devtype, GSList *list)
567 {
568 	GError *err = NULL;
569 	const gchar *ent;
570 	struct fp_dscv_print *print;
571 
572 	GDir *dir = g_dir_open(devpath, 0, &err);
573 	if (!dir) {
574 		fp_err("opendir %s failed: %s", devpath, err->message);
575 		g_error_free(err);
576 		return list;
577 	}
578 
579 	while ((ent = g_dir_read_name(dir))) {
580 		/* ent is an 1 hex character fp_finger code */
581 		guint64 val;
582 		enum fp_finger finger;
583 		gchar *endptr;
584 
585 		if (*ent == 0 || strlen(ent) != 1)
586 			continue;
587 
588 		val = g_ascii_strtoull(ent, &endptr, 16);
589 		if (endptr == ent || !FP_FINGER_IS_VALID(val)) {
590 			fp_dbg("skipping print file %s", ent);
591 			continue;
592 		}
593 
594 		finger = (enum fp_finger) val;
595 		print = g_malloc(sizeof(*print));
596 		print->driver_id = driver_id;
597 		print->devtype = devtype;
598 		print->path = g_build_filename(devpath, ent, NULL);
599 		print->finger = finger;
600 		list = g_slist_prepend(list, print);
601 	}
602 
603 	g_dir_close(dir);
604 	return list;
605 }
606 
scan_driver_store_dir(char * drvpath,uint16_t driver_id,GSList * list)607 static GSList *scan_driver_store_dir(char *drvpath, uint16_t driver_id,
608 	GSList *list)
609 {
610 	GError *err = NULL;
611 	const gchar *ent;
612 
613 	GDir *dir = g_dir_open(drvpath, 0, &err);
614 	if (!dir) {
615 		fp_err("opendir %s failed: %s", drvpath, err->message);
616 		g_error_free(err);
617 		return list;
618 	}
619 
620 	while ((ent = g_dir_read_name(dir))) {
621 		/* ent is an 8 hex character devtype */
622 		guint64 val;
623 		uint32_t devtype;
624 		gchar *endptr;
625 		gchar *path;
626 
627 		if (*ent == 0 || strlen(ent) != 8)
628 			continue;
629 
630 		val = g_ascii_strtoull(ent, &endptr, 16);
631 		if (endptr == ent) {
632 			fp_dbg("skipping devtype %s", ent);
633 			continue;
634 		}
635 
636 		devtype = (uint32_t) val;
637 		path = g_build_filename(drvpath, ent, NULL);
638 		list = scan_dev_store_dir(path, driver_id, devtype, list);
639 		g_free(path);
640 	}
641 
642 	g_dir_close(dir);
643 	return list;
644 }
645 
646 /** \ingroup dscv_print
647  * Scans the users home directory and returns a list of prints that were
648  * previously saved using fp_print_data_save().
649  * \returns a NULL-terminated list of discovered prints, must be freed with
650  * fp_dscv_prints_free() after use.
651  */
fp_discover_prints(void)652 API_EXPORTED struct fp_dscv_print **fp_discover_prints(void)
653 {
654 	GDir *dir;
655 	const gchar *ent;
656 	GError *err = NULL;
657 	GSList *tmplist = NULL;
658 	GSList *elem;
659 	unsigned int tmplist_len;
660 	struct fp_dscv_print **list;
661 	unsigned int i;
662 
663 	if (!base_store)
664 		storage_setup();
665 
666 	dir = g_dir_open(base_store, 0, &err);
667 	if (!dir) {
668 		fp_err("opendir %s failed: %s", base_store, err->message);
669 		g_error_free(err);
670 		return NULL;
671 	}
672 
673 	while ((ent = g_dir_read_name(dir))) {
674 		/* ent is a 4 hex digit driver_id */
675 		gchar *endptr;
676 		gchar *path;
677 		guint64 val;
678 		uint16_t driver_id;
679 
680 		if (*ent == 0 || strlen(ent) != 4)
681 			continue;
682 
683 		val = g_ascii_strtoull(ent, &endptr, 16);
684 		if (endptr == ent) {
685 			fp_dbg("skipping drv id %s", ent);
686 			continue;
687 		}
688 
689 		driver_id = (uint16_t) val;
690 		path = g_build_filename(base_store, ent, NULL);
691 		tmplist = scan_driver_store_dir(path, driver_id, tmplist);
692 		g_free(path);
693 	}
694 
695 	g_dir_close(dir);
696 	tmplist_len = g_slist_length(tmplist);
697 	list = g_malloc(sizeof(*list) * (tmplist_len + 1));
698 	elem = tmplist;
699 	for (i = 0; i < tmplist_len; i++, elem = g_slist_next(elem))
700 		list[i] = elem->data;
701 	list[tmplist_len] = NULL; /* NULL-terminate */
702 
703 	g_slist_free(tmplist);
704 	return list;
705 }
706 
707 /** \ingroup dscv_print
708  * Frees a list of discovered prints. This function also frees the discovered
709  * prints themselves, so make sure you do not use any discovered prints
710  * after calling this function.
711  * \param prints the list of discovered prints. If NULL, function simply
712  * returns.
713  */
fp_dscv_prints_free(struct fp_dscv_print ** prints)714 API_EXPORTED void fp_dscv_prints_free(struct fp_dscv_print **prints)
715 {
716 	int i;
717 	struct fp_dscv_print *print;
718 
719 	if (!prints)
720 		return;
721 
722 	for (i = 0; (print = prints[i]); i++) {
723 		if (print)
724 			g_free(print->path);
725 		g_free(print);
726 	}
727 	g_free(prints);
728 }
729 
730 /** \ingroup dscv_print
731  * Gets the \ref driver_id "driver ID" for a discovered print. The driver ID
732  * indicates which driver the print originally came from. The print is only
733  * usable with a device controlled by that driver.
734  * \param print the discovered print
735  * \returns the driver ID of the driver compatible with the print
736  */
fp_dscv_print_get_driver_id(struct fp_dscv_print * print)737 API_EXPORTED uint16_t fp_dscv_print_get_driver_id(struct fp_dscv_print *print)
738 {
739 	return print->driver_id;
740 }
741 
742 /** \ingroup dscv_print
743  * Gets the \ref devtype "devtype" for a discovered print. The devtype
744  * represents which type of device under the parent driver is compatible
745  * with the print.
746  * \param print the discovered print
747  * \returns the devtype of the device range compatible with the print
748  */
fp_dscv_print_get_devtype(struct fp_dscv_print * print)749 API_EXPORTED uint32_t fp_dscv_print_get_devtype(struct fp_dscv_print *print)
750 {
751 	return print->devtype;
752 }
753 
754 /** \ingroup dscv_print
755  * Gets the finger code for a discovered print.
756  * \param print discovered print
757  * \returns a finger code from #fp_finger
758  */
fp_dscv_print_get_finger(struct fp_dscv_print * print)759 API_EXPORTED enum fp_finger fp_dscv_print_get_finger(struct fp_dscv_print *print)
760 {
761 	return print->finger;
762 }
763 
764 /** \ingroup dscv_print
765  * Removes a discovered print from disk. After successful return of this
766  * function, functions such as fp_dscv_print_get_finger() will continue to
767  * operate as before, however calling fp_print_data_from_dscv_print() will
768  * fail for obvious reasons.
769  * \param print the discovered print to remove from disk
770  * \returns 0 on success, negative on error
771  */
fp_dscv_print_delete(struct fp_dscv_print * print)772 API_EXPORTED int fp_dscv_print_delete(struct fp_dscv_print *print)
773 {
774 	int r;
775 	fp_dbg("remove at %s", print->path);
776 	r = g_unlink(print->path);
777 	if (r < 0)
778 		fp_dbg("unlink failed with error %d", r);
779 
780 	/* FIXME: cleanup empty directory */
781 	return r;
782 }
783 
784