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